/*jshint smarttabs:true, eqeqeq:false, eqnull:true, laxbreak:true*/

(function(window, document, jqLite, undefined) {
	// To allow non strict code to be concatenated together with vx into a single file
	'use strict';
	////////////////////////////////////
	// private Utility
	///////////////////////////////////

	/**
	 * @vxdoc function
	 * @name vx.lowercase
	 * @function
	 *
	 * @description Converts the specified string to lowercase.
	 * @param {string} string String to be converted to lowercase.
	 * @returns {string} Lowercased string.
	 */
	var lowercase = function(string) {
		return isString(string) ? string.toLowerCase() : string;
	};

	/**
	 * @vxdoc function
	 * @name vx.uppercase
	 * @function
	 *
	 * @description Converts the specified string to uppercase.
	 * @param {string} string String to be converted to uppercase.
	 * @returns {string} Uppercased string.
	 */
	var uppercase = function(string) {
		return isString(string) ? string.toUpperCase() : string;
	};

	// String#toLowerCase and String#toUpperCase don't produce correct results in browsers with Turkish
	// locale, for this reason we need to detect this case and redefine lowercase/uppercase methods
	// with correct but slower alternatives.
	if ('i' !== 'I'.toLowerCase()) {
		lowercase = function(s) {
			return isString(s) ? s.replace(/[A-Z]/g, function(ch) {
				return String.fromCharCode(ch.charCodeAt(0) | 32);
			}) : s;
		};
		uppercase = function(s) {
			return isString(s) ? s.replace(/[a-z]/g, function(ch) {
				return String.fromCharCode(ch.charCodeAt(0) & ~32);
			}) : s;
		};
	}

	var/*Error = window.Error, */ _slice = [].slice, _toString = Object.prototype.toString, _nodeName, // aliases
	msie = int((/msie (\d+)/.exec(lowercase(window.navigator.userAgent)) || [])[1]), escape = window.escape, unescape = window.unescape,
	// major version number for IE or NaN for others
	hashId = ['0', '0', '0'], scopeId = ['0', '0', '0'], inputId = ['0', '0', '0'], VID = ['0', '0', '0', '0', '0', '0'];

	if ( typeof document.getAttribute == 'undefined')
		document.getAttribute = function() {
		};

	if (msie < 9) {
		_nodeName = function(element) {
			element = element.nodeName ? element : element[0];
			return (element.scopeName && element.scopeName != 'HTML') ? //
			uppercase(element.scopeName + ':' + element.nodeName) : element.nodeName;
		};
	} else {
		_nodeName = function(element) {
			return element.nodeName ? element.nodeName : element[0].nodeName;
		};
	}

	/**
	 * @description
	 *
	 * This object extends the error class and provides interpolation capability
	 * to make it easier to write and read Error messages within vx. It can
	 * be called as follows:
	 *
	 * throw vError(13, 'This {0} is {1}', foo, bar);
	 *
	 * The above will replace {0} with the value of foo, and {1} with the value of
	 * bar. The object is not restricted in the number of arguments it can take.
	 *
	 * If fewer arguments are specified than necessary for interpolation, the extra
	 * interpolation markers will be preserved in the final string.
	 *
	 * @param {...} arguments The first argument to this object is the error
	 *     number, the second argument the message with templated points for
	 *     Interpolation (of the for {0} for the first, {1} for the second and
	 *     so on). The second argument onwards are interpolated into the error
	 *     message string in order.
	 */
	function vError() {
		var message = '[VX_ERR_' + arguments[0] + '] ' + arguments[1], i = 0, l = arguments.length - 2, curlyRegexp, arg;

		for (; i < l; i++) {
			curlyRegexp = new RegExp("\\{" + i + "\\}", "gm");
			arg = arguments[i + 2];

			if (isFunction(arg)) {
				arg = arg.toString().replace(/ \{[\s\S]*$/, '');
			} else if (!isString(arg)) {
				arg = toJson(arg);
			}

			message = message.replace(curlyRegexp, arg);
		}

		// even if we are called as constructor we can bypass the new vError instance and return
		// an instance of a real Error that contains correct stack info + extra frame for vError call
		// TODO(i): can we rewrite the stack string to remove vError frame?
		return new Error(message);
	}

	function int(str) {
		return parseInt(str, 10);
	}

	function cleanupClosure(obj) {
		for (var i in obj) {
			if (!obj.hasOwnProperty(i))
				continue;
			if (isFunction(obj[i])) {
				obj[i] = noop;
			} else {
				obj[i] = undefined;
			}
		}
	}

	function repaintFactory(el) {
		return function() {
			// now just find IE8 does not render after $digest, so change body's class, let do it.
			// IE9 radio also not render
			if (msie/* === 8*/) {
				repaint(el);
			}
		};
	}

	function repaint(el) {
		var clazz = 'vx-repaint-fix';
		el.addClass(clazz);
		window.setTimeout(function() {
			el.removeClass(clazz);
		}, 1);
	}

	function now() {
		return new Date().getTime();
	}

	/**
	 * when using forEach the params are value, key, but it is often useful to have key, value.
	 * @param {function(string, *)} iteratorFn
	 * @returns {function(*, string)}
	 */
	function reverseParams(iteratorFn) {
		return function(value, key) {
			iteratorFn(key, value);
		};
	}

	function supportObject(delegate) {
		return function(key, value) {
			if (isObject(key)) {
				forEach(key, reverseParams(delegate));
			} else {
				return delegate(key, value);
			}
		};
	}

	/**
	 * A consistent way of creating unique IDs in vx. The ID is a sequence of alpha numeric
	 * characters such as '012ABC'. The reason why we are not using simply a number counter is that
	 * the number string gets longer over time, and it can also overflow, where as the the nextId
	 * will grow much slower, it is a string, and it will never overflow.
	 *
	 * @returns an unique alpha-numeric string
	 */
	function nextUid(uid) {
		var index = uid.length;
		var digit;

		while (index) {
			index--;
			digit = uid[index].charCodeAt(0);
			if (digit == 57 /*'9'*/) {
				uid[index] = 'A';
				return uid.join('');
			}
			if (digit == 90 /*'Z'*/) {
				uid[index] = '0';
			} else {
				uid[index] = String.fromCharCode(digit + 1);
				return uid.join('');
			}
		}
		uid.unshift('1');
		//overflow and then prepend 1 bit as 1
		return uid.join('');
	}

	/**
	 * Set or clear the hashkey for an object.
	 * @param obj object
	 * @param h the hashkey (!truthy to delete the hashkey)
	 */
	function setHashKey(obj, h) {
		if (h) {
			obj.$$hashKey = h;
		} else {
			delete obj.$$hashKey;
		}
	}

	// Generates a random UUID
	function uuid() {
		// Logic borrowed from http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript/2117523#2117523
		return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function(c) {
			var r = Math.random() * 16 | 0, v = c === "x" ? r : (r & 0x3 | 0x8);
			return v.toString(16);
		});
	}

	function map(obj, iterator, context) {
		var results = [];
		forEach(obj, function(value, index, list) {
			results.push(iterator.call(context, value, index, list));
		});
		return results;
	}

	function sortedKeys(obj) {
		var keys = [];
		for (var key in obj) {
			if (obj.hasOwnProperty(key)) {
				keys.push(key);
			}
		}
		return keys.sort();
	}

	function forEachSorted(obj, iterator, context) {
		var keys = sortedKeys(obj);
		for (var i = 0, len = keys.length; i < len; i++) {
			iterator.call(context, obj[keys[i]], keys[i]);
		}
		return keys;
	}

	/**
	 * @description
	 * Determines the number of elements in an array, the number of properties an object has, or
	 * the length of a string.
	 *
	 * Note: This function is used to augment the Object type in VX expressions. See
	 * {@link vx.Object} for more information about VX arrays.
	 *
	 * @param {Object|Array|string} obj Object, array, or string to inspect.
	 * @param {boolean} [ownPropsOnly=false] Count only "own" properties in an object
	 * @returns {number} The size of `obj` or `0` if `obj` is neither an object nor an array.
	 */
	function size(obj, ownPropsOnly) {
		var _size = 0, key;
		if (isArray(obj) || isString(obj)) {
			return obj.length;
		} else if (isObject(obj)) {
			for (key in obj)
			if (!ownPropsOnly || obj.hasOwnProperty(key))
				_size++;
		}
		return _size;
	}

	function arrayRemove(array, value) {
		var index = indexOf(array, value);
		if (index >= 0)
			array.splice(index, 1);
		return value;
	}

	function sliceArgs(args, startIndex) {
		return _slice.call(args, startIndex || 0);
	}

	function _fastInvoke(fnPtr, context, args) {
		// Performance optimization: http://jsperf.com/apply-vs-call-vs-invoke
		switch (context && fnPtr.apply ? -1 : args.length) {
			case  0:
				return fnPtr();
			case  1:
				return fnPtr(args[0]);
			case  2:
				return fnPtr(args[0], args[1]);
			case  3:
				return fnPtr(args[0], args[1], args[2]);
			case  4:
				return fnPtr(args[0], args[1], args[2], args[3]);
			case  5:
				return fnPtr(args[0], args[1], args[2], args[3], args[4]);
			case  6:
				return fnPtr(args[0], args[1], args[2], args[3], args[4], args[5]);
			case  7:
				return fnPtr(args[0], args[1], args[2], args[3], args[4], args[5], args[6]);
			case  8:
				return fnPtr(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7]);
			case  9:
				return fnPtr(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8]);
			case 10:
				return fnPtr(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9]);
			default:
				return fnPtr.apply(context, args);
		}
	}

	/**
	 * @returns {string} Returns the string representation of the element.
	 */
	function startingTag(element) {
		element = jqLite(element).clone();
		try {
			// turns out IE does not let you set .html() on elements which
			// are not allowed to have children. So we just ignore it.
			element.html('');
		} catch(e) {
		}
		// As Per DOM Standards
		var TEXT_NODE = 3;
		var elemHtml = jqLite('<div>').append(element).html();
		try {
			return element[0].nodeType === TEXT_NODE ? lowercase(elemHtml) : elemHtml.
			match(/^(<[^>]+>)/)[1].replace(/^<([\w\-]+)/, function(match, nodeName) {
				return '<' + lowercase(nodeName);
			});
		} catch(e) {
			return lowercase(elemHtml);
		}
	}

	var SNAKE_CASE_REGEXP = /[A-Z]/g;
	function snake_case(name, separator) {
		separator = separator || '_';
		return name.replace(SNAKE_CASE_REGEXP, function(letter, pos) {
			return ( pos ? separator : '') + letter.toLowerCase();
		});
	}

	/**
	 * Converts snake_case to camelCase.
	 * Also there is special case for Moz prefix starting with upper case letter.
	 * @param name Name to normalize
	 */
	var SPECIAL_CHARS_REGEXP = /([\:\-\_]+(.))/g;
	var MOZ_HACK_REGEXP = /^moz([A-Z])/;
	function camelCase(name) {
		return name.replace(SPECIAL_CHARS_REGEXP, function(_, separator, letter, offset) {
			return offset ? letter.toUpperCase() : letter;
		}).replace(MOZ_HACK_REGEXP, 'Moz$1');
	}

	/**
	 * throw error if the argument is falsy.
	 */
	function assertArg(arg, name, reason) {
		if (!arg) {
			throw vError(1, "Argument '{0}' is {1}", (name || '?'), (reason || "required"));
		}
		return arg;
	}

	function assertArgFn(arg, name, acceptArrayAnnotation) {
		if (acceptArrayAnnotation && isArray(arg)) {
			arg = arg[arg.length - 1];
		}
		assertArg(isFunction(arg), name, 'not a function, got ' + (arg && typeof arg == 'object' ? arg.constructor.name || 'Object' : typeof arg));
		return arg;
	}

	function padNumber(num, digits, trim) {
		var neg = '';
		if (num < 0) {
			neg = '-';
			num = -num;
		}
		num = '' + num;
		while (num.length < digits)
		num = '0' + num;
		if (trim)
			num = num.substr(num.length - digits);
		return neg + num;
	}

	/**
	 * Computes a hash of an 'obj'.
	 * Hash of a:
	 *  string is string
	 *  number is number as string
	 *  object is either result of calling $$hashKey function on the object or uniquely generated id,
	 *         that is also assigned to the $$hashKey property of the object.
	 *
	 * @param obj
	 * @returns {string} hash string such that the same input will have the same hash string.
	 *         The resulting string key is in 'type:hashKey' format.
	 */
	function hashKey(obj) {
		var objType = typeof obj, key;
		if (objType == 'object' && obj !== null) {
			if ( typeof ( key = obj.$$hashKey) == 'function') {
				// must invoke on object to keep the right this
				key = obj.$$hashKey();
			} else if (key === undefined) {
				key = obj.$$hashKey = nextUid(hashId);
			}
		} else {
			key = obj;
		}
		return objType + ':' + key;
	}

	/**
	 * HashMap which can use objects as keys
	 */
	function HashMap(array) {
		forEach(array, this.put, this);
	}


	HashMap.prototype = {
		/**
		 * Store key value pair
		 * @param key key to store can be any type
		 * @param value value to store can be any type
		 */
		put : function(key, value) {
			this[hashKey(key)] = value;
		},
		/**
		 * @param key
		 * @returns the value for the key
		 */
		get : function(key) {
			return this[hashKey(key)];
		},
		/**
		 * Remove the key/value pair
		 * @param key
		 */
		remove : function(key) {
			var value = this[ key = hashKey(key)];
			delete this[key];
			return value;
		}
	};

	////////////////////////////////////
	// public Utility
	///////////////////////////////////
	// vx handle
	var vx = window.vx || (window.vx = {});

	function define(name, obj) {
		var part, c = window, parts;
		if (name.length > 0) {
			parts = name.split(".");
			for (var i = 0, ii = parts.length; i < ii; i++) {
				part = parts[i];
				c = c[part] || (c[part] = {});
			}
		}
		var a = [];
		for (var e in obj) {
			if (obj.hasOwnProperty(e))
				a.push(c[e] = obj[e]);
		}
		return a;
	}

	/**
	 * @private
	 * @param {*} obj
	 * @return {boolean} Returns true if `obj` is an array or array-like object (NodeList, Arguments, ...)
	 */
	function isArrayLike(obj) {
		if (!obj || ( typeof obj.length !== 'number'))
			return false;

		// We have on object which has length property. Should we treat it as array?
		if ( typeof obj.hasOwnProperty != 'function' && typeof obj.constructor != 'function') {
			// This is here for IE8: it is a bogus object treat it as array;
			return true;
		} else {
			return obj instanceof jqLite || // JQLite
			_toString.call(obj) !== '[object Object]' || // some browser native object
			typeof obj.callee === 'function';
			// arguments (on IE8 looks like regular obj)
		}
	}

	/**
	 * @vxdoc function
	 * @name vx.forEach
	 * @function
	 *
	 * @description
	 * Invokes the `iterator` function once for each item in `obj` collection, which can be either an
	 * object or an array. The `iterator` function is invoked with `iterator(value, key)`, where `value`
	 * is the value of an object property or an array element and `key` is the object property key or
	 * array element index. Specifying a `context` for the function is optional.
	 *
	 * Note: this function was previously known as `vx.foreach`.
	 *
	 <pre>
	 var values = {name: 'misko', gender: 'male'};
	 var log = [];
	 vx.forEach(values, function(value, key){
	 this.push(key + ': ' + value);
	 }, log);
	 expect(log).toEqual(['name: misko', 'gender:male']);
	 </pre>
	 *
	 * @param {Object|Array} obj Object to iterate over.
	 * @param {Function} iterator Iterator function.
	 * @param {Object=} context Object to become context (`this`) for the iterator function.
	 * @returns {Object|Array} Reference to `obj`.
	 */

	function forEach(obj, iterator, context) {
		var key, len;
		if (obj) {
			if (isFunction(obj)) {
				for (key in obj) {
					if (key != 'prototype' && key != 'length' && key != 'name' && obj.hasOwnProperty(key)) {
						iterator.call(context, obj[key], key);
					}
				}
			} else if (obj.forEach && obj.forEach !== forEach) {
				obj.forEach(iterator, context);
			} else if (isArrayLike(obj)) {
				for ( key = 0, len = obj.length; key < len; key++)
					iterator.call(context, obj[key], key);
			} else {
				for (key in obj)
				if (obj.hasOwnProperty(key)) {
					iterator.call(context, obj[key], key);
				}
			}
		}
		return obj;
	}

	/**
	 * @vxdoc function
	 * @name vx.extend
	 * @function
	 *
	 * @description
	 * Extends the destination object `dst` by copying all of the properties from the `src` object(s)
	 * to `dst`. You can specify multiple `src` objects.
	 *
	 * @param {Object} dst Destination object.
	 * @param {...Object} src Source object(s).
	 * @returns {Object} Reference to `dst`.
	 */
	function extend(dst) {
		var h = dst.$$hashKey;
		forEach(arguments, function(obj) {
			if (obj !== dst) {
				forEach(obj, function(value, key) {
					dst[key] = value;
				});
			}
		});
		setHashKey(dst, h);
		return dst;
	}

	function inherit(parent, extra) {
		return extend(new (extend(function() {}, {prototype:parent}))(), extra);
	}

	/**
	 * @vxdoc function
	 * @name vx.noop
	 * @function
	 *
	 * @description
	 * A function that performs no operations. This function can be useful when writing code in the
	 * functional style.
	 <pre>
	 function foo(callback) {
	 var result = calculateResult();
	 (callback || vx.noop)(result);
	 }
	 </pre>
	 */
	noop.$inject = [];
	function noop() {
	}

	/**
	 * @vxdoc function
	 * @name vx.identity
	 * @function
	 *
	 * @description
	 * A function that returns its first argument. This function is useful when writing code in the
	 * functional style.
	 *
	 <pre>
	 function transformer(transformationFn, value) {
	 return (transformationFn || identity)(value);
	 };
	 </pre>
	 */
	identity.$inject = [];
	function identity($) {
		return $;
	}

	function valueFn(value) {
		return function() {
			return value;
		};
	}

	/**
	 * @vxdoc function
	 * @name vx.isUndefined
	 * @function
	 *
	 * @description
	 * Determines if a reference is undefined.
	 *
	 * @param {*} value Reference to check.
	 * @returns {boolean} True if `value` is undefined.
	 */
	function isUndefined(value) {
		return typeof value == 'undefined';
	}

	function isEmpty(value) {
		return isUndefined(value) || value === '' || value === null || value !== value;
	}

	/**
	 * @vxdoc function
	 * @name vx.isDefined
	 * @function
	 *
	 * @description
	 * Determines if a reference is defined.
	 *
	 * @param {*} value Reference to check.
	 * @returns {boolean} True if `value` is defined.
	 */
	function isDefined(value) {
		return typeof value != 'undefined';
	}

	/**
	 * @vxdoc function
	 * @name vx.isObject
	 * @function
	 *
	 * @description
	 * Determines if a reference is an `Object`. Unlike `typeof` in JavaScript, `null`s are not
	 * considered to be objects.
	 *
	 * @param {*} value Reference to check.
	 * @returns {boolean} True if `value` is an `Object` but not `null`.
	 */
	function isObject(value) {
		return value != null && typeof value == 'object';
	}

	/**
	 * @vxdoc function
	 * @name vx.isString
	 * @function
	 *
	 * @description
	 * Determines if a reference is a `String`.
	 *
	 * @param {*} value Reference to check.
	 * @returns {boolean} True if `value` is a `String`.
	 */
	function isString(value) {
		return typeof value == 'string';
	}

	/**
	 * @vxdoc function
	 * @name vx.isNumber
	 * @function
	 *
	 * @description
	 * Determines if a reference is a `Number`.
	 *
	 * @param {*} value Reference to check.
	 * @returns {boolean} True if `value` is a `Number`.
	 */
	function isNumber(value) {
		return typeof value == 'number';
	}

	/**
	 * @vxdoc function
	 * @name vx.isDate
	 * @function
	 *
	 * @description
	 * Determines if a value is a date.
	 *
	 * @param {*} value Reference to check.
	 * @returns {boolean} True if `value` is a `Date`.
	 */
	function isDate(value) {
		return _toString.apply(value) == '[object Date]';
	}

	function isRegExp(value) {
		return _toString.apply(value) == '[object RegExp]';
	}

	/**
	 * @vxdoc function
	 * @name vx.isArray
	 * @function
	 *
	 * @description
	 * Determines if a reference is an `Array`.
	 *
	 * @param {*} value Reference to check.
	 * @returns {boolean} True if `value` is an `Array`.
	 */
	function isArray(value) {
		return _toString.apply(value) == '[object Array]';
	}

	/**
	 * @vxdoc function
	 * @name vx.isFunction
	 * @function
	 *
	 * @description
	 * Determines if a reference is a `Function`.
	 *
	 * @param {*} value Reference to check.
	 * @returns {boolean} True if `value` is a `Function`.
	 */
	function isFunction(value) {
		return typeof value == 'function';
	}

	/**
	 * Checks if `obj` is a window object.
	 *
	 * @private
	 * @param {*} obj Object to check
	 * @returns {boolean} True if `obj` is a window obj.
	 */
	function isWindow(obj) {
		return obj && obj.document && obj.location && obj.alert && obj.setInterval;
	}

	function isScope(obj) {
		return obj && obj.$evalAsync && obj.$watch;
	}

	function isFile(obj) {
		return _toString.apply(obj) === '[object File]';
	}

	function isBoolean(value) {
		return typeof value == 'boolean';
	}

	function toBoolean(value) {
		if (value && value.length !== 0) {
			var v = lowercase("" + value);
			value = !(v == 'f' || v == '0' || v == 'false' || v == 'no' || v == 'n' || v == '[]');
		} else {
			value = false;
		}
		return value;
	}

	/**
	 * @vxdoc function
	 * @name vx.isElement
	 * @function
	 *
	 * @description
	 * Determines if a reference is a DOM element (or wrapped jQuery element).
	 *
	 * @param {*} value Reference to check.
	 * @returns {boolean} True if `value` is a DOM element (or wrapped jQuery element).
	 */
	function isElement(node) {
		// we are a direct element or part of jQuery API
		return node && (node.nodeName || (node.bind && node.find));
	}

	function includes(array, obj) {
		return indexOf(array, obj) != -1;
	}

	function indexOf(array, obj) {
		if (array.indexOf)
			return array.indexOf(obj);

		for (var i = 0, len = array.length; i < len; i++) {
			if (obj === array[i])
				return i;
		}
		return -1;
	}

	function trim(value) {
		return isString(value) ? value.replace(/^\s*/, '').replace(/\s*$/, '') : value;
	}

	/**
	 * @vxdoc function
	 * @name vx.copy
	 * @function
	 *
	 * @description
	 * Creates a deep copy of `source`, which should be an object or an array.
	 *
	 * * If no destination is supplied, a copy of the object or array is created.
	 * * If a destination is provided, all of its elements (for array) or properties (for objects)
	 *   are deleted and then all elements/properties from the source are copied to it.
	 * * If  `source` is not an object or array, `source` is returned.
	 *
	 * Note: this function is used to augment the Object type in VX expressions. See
	 * {@link vx.$filter} for more information about VX arrays.
	 *
	 * @param {*} source The source that will be used to make a copy.
	 *                   Can be any type, including primitives, `null`, and `undefined`.
	 * @param {(Object|Array)=} destination Destination into which the source is copied. If
	 *     provided, must be of the same type as `source`.
	 * @returns {*} The copy or updated `destination`, if `destination` was specified.
	 */
	function copy(source, destination) {
		if (isWindow(source) || isScope(source))
			throw vError(2, "Can't copy! Making copies of Window or Scope instances is not supported.");
		if (!destination) {
			destination = source;
			if (source) {
				if (isArray(source)) {
					destination = copy(source, []);
				} else if (isDate(source)) {
					destination = new Date(source.getTime());
				} else if (isObject(source)) {
					destination = copy(source, {});
				}
			}
		} else {
			if (source === destination)
				throw vError(3, "Can't copy! Source and destination are identical.");
			if (isArray(source)) {
				destination.length = 0;
				for (var i = 0; i < source.length; i++) {
					destination.push(copy(source[i]));
				}
			} else {
				var h = destination.$$hashKey;
				forEach(destination, function(value, key) {
					delete destination[key];
				});
				for (var key in source) {
					destination[key] = copy(source[key]);
				}
				setHashKey(destination, h);
			}
		}
		return destination;
	}

	/**
	 * Create a shallow copy of an object
	 */
	function shallowCopy(src, dst) {
		dst = dst || {};
		for (var key in src) {
			if (src.hasOwnProperty(key) && key.substr(0, 2) !== '$$') {
				dst[key] = src[key];
			}
		}
		return dst;
	}

	/**
	 * @vxdoc function
	 * @name vx.equals
	 * @function
	 *
	 * @description
	 * Determines if two objects or two values are equivalent. Supports value types, arrays and
	 * objects.
	 *
	 * Two objects or values are considered equivalent if at least one of the following is true:
	 *
	 * * Both objects or values pass `===` comparison.
	 * * Both objects or values are of the same type and all of their properties pass `===` comparison.
	 * * Both values are NaN. (In JavasScript, NaN == NaN => false. But we consider two NaN as equal)
	 *
	 * During a property comparison, properties of `function` type and properties with names
	 * that begin with `$` are ignored.
	 *
	 * Scope and DOMWindow objects are being compared only by identify (`===`).
	 *
	 * @param {*} o1 Object or value to compare.
	 * @param {*} o2 Object or value to compare.
	 * @returns {boolean} True if arguments are equal.
	 */
	function equals(o1, o2) {
		if (o1 === o2)
			return true;
		if (o1 === null || o2 === null)
			return false;
		if (o1 !== o1 && o2 !== o2)// NaN === NaN
			return true;
		var t1 = typeof o1, t2 = typeof o2, length, key, keySet;
		if (t1 == t2) {
			if (t1 == 'object') {
				if (isArray(o1)) {
					if (( length = o1.length) == o2.length) {
						for ( key = 0; key < length; key++) {
							if (!equals(o1[key], o2[key]))
								return false;
						}
						return true;
					}
				} else if (isDate(o1)) {
					return isDate(o2) && o1.getTime() == o2.getTime();
				} else {
					if (isScope(o1) || isScope(o2) || isWindow(o1) || isWindow(o2))
						return false;
					keySet = {};
					for (key in o1) {
						if (key.charAt(0) === '$' || isFunction(o1[key]))
							continue;
						if (!equals(o1[key], o2[key]))
							return false;
						keySet[key] = true;
					}
					for (key in o2) {
						if (!keySet[key] && key.charAt(0) !== '$' && o2[key] !== undefined && !isFunction(o2[key]))
							return false;
					}
					return true;
				}
			}
		}
		return false;
	}

	/**
	 * @vxdoc function
	 * @name vx.bind
	 * @function
	 *
	 * @description
	 * Returns a function which calls function `fn` bound to `self` (`self` becomes the `this` for
	 * `fn`). You can supply optional `args` that are prebound to the function. This feature is also
	 * known as [function currying](http://en.wikipedia.org/wiki/Currying).
	 *
	 * @param {Object} self Context which `fn` should be evaluated in.
	 * @param {function()} fn Function to be bound.
	 * @param {...*} args Optional arguments to be prebound to the `fn` function call.
	 * @returns {function()} Function that wraps the `fn` with all the specified bindings.
	 */
	function bind(self, fn) {
		var curryArgs = arguments.length > 2 ? sliceArgs(arguments, 2) : [];
		if (isFunction(fn) && !( fn instanceof RegExp)) {
			return curryArgs.length ? function() {
				return arguments.length ? fn.apply(self, curryArgs.concat(_slice.call(arguments, 0))) : fn.apply(self, curryArgs);
			} : function() {
				return arguments.length ? fn.apply(self, arguments) : fn.call(self);
			};
		} else {
			// in IE, native methods are not functions so they cannot be bound (note: they don't need to be)
			return fn;
		}
	}

	var URL_MATCH = /^([^:]+):\/\/(\w+:{0,1}\w*@)?(\{?[\w\.\-]*\}?)(:([0-9]+))?(\/[^\?#]*)?(\?([^#]*))?(#(.*))?$/, DEFAULT_PORTS = {
		'http' : 80,
		'https' : 443,
		'ftp' : 21
	};

	var URL = (function() {
		parseUrl.DEFAULT_PORTS = DEFAULT_PORTS;
		function parseUrl(url) {
			var match = URL_MATCH.exec(url);
			match = {
				protocol : match[1],
				host : match[3],
				port : int(match[5]) || DEFAULT_PORTS[match[1]] || null,
				path : match[6] || '/',
				search : match[8],
				hash : match[10]
			};
			return match;
		}

		return parseUrl;
	})();

	function concat(array1, array2, index) {
		return array1.concat(_slice.call(array2, index));
	}

	///////////////////////////////////////
	// Expr Parser
	//////////////////////////////////////
	/**
	 * Return the value accessible from the object by path. Any undefined traversals are ignored
	 * @param {Object} obj starting object
	 * @param {string} path path to traverse
	 * @param {boolean=true} bindFnToScope
	 * @returns value as accessible by path
	 */
	function getter(obj, path, bindFnToScope) {
		if (!path || !obj)
			return obj;
		var keys = path.split('.'), key, lastInstance = obj, len = keys.length;
		for (var i = 0; i < len; i++) {
			key = keys[i];
			if (obj) {
				obj = (lastInstance = obj)[key];
			}
		}
		//obj = EXPR.getter(path)(obj);
		if (!bindFnToScope && isFunction(obj)) {
			return bind(lastInstance, obj);
		}
		return obj;
	}

	var EXPR = (function() {

		var OPERATORS = {
			'null' : function() {
				return null;
			},
			'true' : function() {
				return true;
			},
			'false' : function() {
				return false;
			},
			undefined : noop,
			'+' : function(self, locals, a, b) {
				a = a(self, locals);
				b = b(self, locals);
				if (isDefined(a)) {
					if (isDefined(b)) {
						return a + b;
					}
					return a;
				}
				return isDefined(b) ? b : undefined;
			},
			'-' : function(self, locals, a, b) {
				a = a(self, locals);
				b = b(self, locals);
				return (isDefined(a) ? a : 0) - (isDefined(b) ? b : 0);
			},
			'*' : function(self, locals, a, b) {
				return a(self, locals) * b(self, locals);
			},
			'/' : function(self, locals, a, b) {
				return a(self, locals) / b(self, locals);
			},
			'%' : function(self, locals, a, b) {
				return a(self, locals) % b(self, locals);
			},
			'^' : function(self, locals, a, b) {
				return a(self, locals) ^ b(self, locals);
			},
			'=' : noop,
			'===' : function(self, locals, a, b) {
				return a(self, locals) === b(self, locals);
			},
			'!==' : function(self, locals, a, b) {
				return a(self, locals) !== b(self, locals);
			},
			'==' : function(self, locals, a, b) {
				return a(self, locals) == b(self, locals);
			},
			'!=' : function(self, locals, a, b) {
				return a(self, locals) != b(self, locals);
			},
			'<' : function(self, locals, a, b) {
				return a(self, locals) < b(self, locals);
			},
			'>' : function(self, locals, a, b) {
				return a(self, locals) > b(self, locals);
			},
			'<=' : function(self, locals, a, b) {
				return a(self, locals) <= b(self, locals);
			},
			'>=' : function(self, locals, a, b) {
				return a(self, locals) >= b(self, locals);
			},
			'&&' : function(self, locals, a, b) {
				return a(self, locals) && b(self, locals);
			},
			'||' : function(self, locals, a, b) {
				return a(self, locals) || b(self, locals);
			},
			'&' : function(self, locals, a, b) {
				return a(self, locals) & b(self, locals);
			},
			//    '|':function(self, locals, a,b){return a|b;},
			'|' : function(self, locals, a, b) {
				return b(self, locals)(self, locals, a(self, locals));
			},
			'!' : function(self, locals, a) {
				return !a(self, locals);
			}
		};
		var ESCAPE = {
			"n" : "\n",
			"f" : "\f",
			"r" : "\r",
			"t" : "\t",
			"v" : "\v",
			"'" : "'",
			'"' : '"'
		};

		function lex(text, csp) {
			var tokens = [], token, index = 0, json = [], ch, lastCh = ':';
			// can start regexp

			while (index < text.length) {
				ch = text.charAt(index);
				if (is('"\'')) {
					readString(ch);
				} else if (isDigit(ch) || is('.') && isDigit(peek())) {
					readNumber();
				} else if (isIdent(ch)) {
					readIdent();
					// identifiers can only be if the preceding char was a { or ,
					if (was('{,') && json[0] == '{' && ( token = tokens[tokens.length - 1])) {
						token.json = token.text.indexOf('.') == -1;
					}
				} else if (is('(){}[].,;:?')) {
					tokens.push({
						index : index,
						text : ch,
						json : (was(':[,') && is('{[')) || is('}]:,')
					});
					if (is('{['))
						json.unshift(ch);
					if (is('}]'))
						json.shift();
					index++;
				} else if (isWhitespace(ch)) {
					index++;
					continue;
				} else {
					var ch2 = ch + peek(), ch3 = ch2 + peek(2), fn = OPERATORS[ch], fn2 = OPERATORS[ch2], fn3 = OPERATORS[ch3];
					if (fn3) {
						tokens.push({
							index : index,
							text : ch3,
							fn : fn3
						});
						index += 3;
					} else if (fn2) {
						tokens.push({
							index : index,
							text : ch2,
							fn : fn2
						});
						index += 2;
					} else if (fn) {
						tokens.push({
							index : index,
							text : ch,
							fn : fn,
							json : was('[,:') && is('+-')
						});
						index += 1;
					} else {
						throwError("Unexpected next character ", index, index + 1);
					}
				}
				lastCh = ch;
			}
			return tokens;

			function is(chars) {
				return chars.indexOf(ch) != -1;
			}

			function was(chars) {
				return chars.indexOf(lastCh) != -1;
			}

			function peek(i) {
				var num = i || 1;
				return index + num < text.length ? text.charAt(index + num) : false;
			}

			function isDigit(ch) {
				return '0' <= ch && ch <= '9';
			}

			function isWhitespace(ch) {
				return ch == ' ' || ch == '\r' || ch == '\t' || ch == '\n' || ch == '\v' || ch == '\u00A0';
				// IE treats non-breaking space as \u00A0
			}

			function isIdent(ch) {
				return 'a' <= ch && ch <= 'z' || 'A' <= ch && ch <= 'Z' || '_' == ch || ch == '$';
			}

			function isExpOperator(ch) {
				return ch == '-' || ch == '+' || isDigit(ch);
			}

			function throwError(error, start, end) {
				end = end || index;
				var colStr = (isDefined(start) ? "s " + start + "-" + index + " [" + text.substring(start, end) + "]" : " " + end);
				throw vError(10, "Lexer Error: {0} at column{1} in expression [{2}].", error, colStr, text);
			}

			function readNumber() {
				var number = "";
				var start = index;
				while (index < text.length) {
					var ch = lowercase(text.charAt(index));
					if (ch == '.' || isDigit(ch)) {
						number += ch;
					} else {
						var peekCh = peek();
						if (ch == 'e' && isExpOperator(peekCh)) {
							number += ch;
						} else if (isExpOperator(ch) && peekCh && isDigit(peekCh) && number.charAt(number.length - 1) == 'e') {
							number += ch;
						} else if (isExpOperator(ch) && (!peekCh || !isDigit(peekCh)) && number.charAt(number.length - 1) == 'e') {
							throwError('Invalid exponent');
						} else {
							break;
						}
					}
					index++;
				}
				number = 1 * number;
				tokens.push({
					index : start,
					text : number,
					json : true,
					fn : function() {
						return number;
					}
				});
			}

			function readIdent() {
				var ident = "", start = index, lastDot, peekIndex, methodName, ch;

				while (index < text.length) {
					ch = text.charAt(index);
					if (ch == '.' || isIdent(ch) || isDigit(ch)) {
						if (ch == '.')
							lastDot = index;
						ident += ch;
					} else {
						break;
					}
					index++;
				}

				//check if this is not a method invocation and if it is back out to last dot
				if (lastDot) {
					peekIndex = index;
					while (peekIndex < text.length) {
						ch = text.charAt(peekIndex);
						if (ch == '(') {
							methodName = ident.substr(lastDot - start + 1);
							ident = ident.substr(0, lastDot - start);
							index = peekIndex;
							break;
						}
						if (isWhitespace(ch)) {
							peekIndex++;
						} else {
							break;
						}
					}
				}

				var token = {
					index : start,
					text : ident
				};

				if (OPERATORS.hasOwnProperty(ident)) {
					token.fn = token.json = OPERATORS[ident];
				} else {
					var getter = getterFn(ident, csp);
					token.fn = extend(function(self, locals) {
						return (getter(self, locals));
					}, {
						assign : function(self, value) {
							return setter(self, ident, value);
						}
					});
				}

				tokens.push(token);

				if (methodName) {
					tokens.push({
						index : lastDot,
						text : '.',
						json : false
					});
					tokens.push({
						index : lastDot + 1,
						text : methodName,
						json : false
					});
				}
			}

			function readString(quote) {
				var start = index;
				index++;
				var string = "", stringFn = function() {
					return string;
				};
				var rawString = quote;
				var escape = false;
				while (index < text.length) {
					var ch = text.charAt(index);
					rawString += ch;
					if (escape) {
						if (ch == 'u') {
							var hex = text.substring(index + 1, index + 5);
							if (!hex.match(/[\da-f]{4}/i))
								throwError("Invalid unicode escape [\\u" + hex + "]");
							index += 4;
							string += String.fromCharCode(parseInt(hex, 16));
						} else {
							var rep = ESCAPE[ch];
							if (rep) {
								string += rep;
							} else {
								string += ch;
							}
						}
						escape = false;
					} else if (ch == '\\') {
						escape = true;
					} else if (ch == quote) {
						index++;
						tokens.push({
							index : start,
							text : rawString,
							string : string,
							json : true,
							fn : stringFn
						});
						return;
					} else {
						string += ch;
					}
					index++;
				}
				throwError("Unterminated quote", start);
			}

		}

		function parser(text, json, $filter, csp) {
			var ZERO = valueFn(0), value, tokens = lex(text, csp), assignment = _assignment, functionCall = _functionCall, //
			fieldAccess = _fieldAccess, objectIndex = _objectIndex, filterChain = _filterChain;
			if (json) {
				// The extra level of aliasing is here, just in case the lexer misses something, so that
				// we prevent any accidental execution in JSON.
				assignment = logicalOR;
				functionCall = fieldAccess = objectIndex = filterChain = function() {
					throwError("is not valid json.json", {
						text : text,
						index : 0
					});
				};
				value = primary();
			} else {
				value = statements();
			}
			if (tokens.length !== 0) {
				throwError("is an unexpected token", tokens[0]);
			}
			value.literal = !!value.literal;
			value.constant = !!value.constant;
			return value;

			//---------------------------------------
			function throwError(msg, token) {
				throw vError(11, "Syntax Error: Token '{0}' {1} at column {2} of the expression [{3}] starting at [{4}].", token.text, msg, (token.index + 1), text, text.substring(token.index));
			}

			function peekToken() {
				if (tokens.length === 0)
					throw vError(12, "Unexpected end of expression: {0}", text);
				return tokens[0];
			}

			function peek(e1, e2, e3, e4) {
				if (tokens.length > 0) {
					var token = tokens[0];
					var t = token.text;
					if (t == e1 || t == e2 || t == e3 || t == e4 || (!e1 && !e2 && !e3 && !e4)) {
						return token;
					}
				}
				return false;
			}

			function expect(e1, e2, e3, e4) {
				var token = peek(e1, e2, e3, e4);
				if (token) {
					if (json && !token.json) {
						throwError("is not valid json.json", token);
					}
					tokens.shift();
					return token;
				}
				return false;
			}

			function consume(e1) {
				if (!expect(e1)) {
					throwError("is unexpected, expecting [" + e1 + "]", peek());
				}
			}

			function unaryFn(fn, right) {
				return extend(function(self, locals) {
					return fn(self, locals, right);
				}, {
					constant : right.constant
				});
			}

			function ternaryFn(left, middle, right) {
				return extend(function(self, locals) {
					return left(self, locals) ? middle(self, locals) : right(self, locals);
				}, {
					constant : left.constant && middle.constant && right.constant
				});
			}

			function binaryFn(left, fn, right) {
				return extend(function(self, locals) {
					return fn(self, locals, left, right);
				}, {
					constant : left.constant && right.constant
				});
			}

			function statements() {
				var _statements = [], fn = function(self, locals) {
					var value;
					for (var i = 0; i < _statements.length; i++) {
						var statement = _statements[i];
						if (statement)
							value = statement(self, locals);
					}
					return value;
				};
				while (true) {
					if (tokens.length > 0 && !peek('}', ')', ';', ']'))
						_statements.push(filterChain());
					if (!expect(';')) {
						// optimize for the common case where there is only one statement.
						// TODO(size): maybe we should not support multiple statements?
						return _statements.length == 1 ? _statements[0] : fn;
					}
				}
			}

			function _filterChain() {
				var left = expression();
				var token;
				while (true) {
					if (( token = expect('|'))) {
						left = binaryFn(left, token.fn, filter());
					} else {
						return left;
					}
				}
			}

			function filter() {
				var token = expect();
				var fn = $filter(token.text);
				var argsFn = [];
				var fnInvoke = function(self, locals, input) {
					var args = [input];
					for (var i = 0; i < argsFn.length; i++) {
						args.push(argsFn[i](self, locals));
					}
					return fn.apply(self, args);
				}, fn1 = function() {
					return fnInvoke;
				};
				while (true) {
					if (( token = expect(':'))) {
						argsFn.push(expression());
					} else {
						return fn1;
					}
				}
			}

			function expression() {
				return assignment();
			}

			function _assignment() {
				var left = ternary();
				var right;
				var token;
				if (( token = expect('='))) {
					if (!left.assign) {
						throwError("implies assignment but [" + text.substring(0, token.index) + "] can not be assigned to", token);
					}
					right = ternary();
					return function(scope, locals) {
						return left.assign(scope, right(scope, locals), locals);
					};
				} else {
					return left;
				}
			}

			function ternary() {
				var left = logicalOR();
				var middle;
				var token;
				if (( token = expect('?'))) {
					middle = ternary();
					if (( token = expect(':'))) {
						return ternaryFn(left, middle, ternary());
					} else {
						throwError('expected :', token);
					}
				} else {
					return left;
				}
			}

			function logicalOR() {
				var left = logicalAND();
				var token;
				while (true) {
					if (( token = expect('||'))) {
						left = binaryFn(left, token.fn, logicalAND());
					} else {
						return left;
					}
				}
			}

			function logicalAND() {
				var left = equality();
				var token;
				if (( token = expect('&&'))) {
					left = binaryFn(left, token.fn, logicalAND());
				}
				return left;
			}

			function equality() {
				var left = relational();
				var token;
				if (( token = expect('==', '!=', '===', '!=='))) {
					left = binaryFn(left, token.fn, equality());
				}
				return left;
			}

			function relational() {
				var left = additive();
				var token;
				if (( token = expect('<', '>', '<=', '>='))) {
					left = binaryFn(left, token.fn, relational());
				}
				return left;
			}

			function additive() {
				var left = multiplicative();
				var token;
				while (( token = expect('+', '-'))) {
					left = binaryFn(left, token.fn, multiplicative());
				}
				return left;
			}

			function multiplicative() {
				var left = unary();
				var token;
				while (( token = expect('*', '/', '%'))) {
					left = binaryFn(left, token.fn, unary());
				}
				return left;
			}

			function unary() {
				var token;
				if (expect('+')) {
					return primary();
				} else if (( token = expect('-'))) {
					return binaryFn(ZERO, token.fn, unary());
				} else if (( token = expect('!'))) {
					return unaryFn(token.fn, unary());
				} else {
					return primary();
				}
			}

			function primary() {
				var _primary;
				if (expect('(')) {
					_primary = filterChain();
					consume(')');
				} else if (expect('[')) {
					_primary = arrayDeclaration();
				} else if (expect('{')) {
					_primary = object();
				} else {
					var token = expect();
					_primary = token.fn;
					if (!_primary) {
						throwError("not a primary expression", token);
					}
					if (token.json) {
						primary.constant = primary.literal = true;
					}
				}

				var next, context;
				while (( next = expect('(', '[', '.'))) {
					if (next.text === '(') {
						_primary = functionCall(_primary, context);
						context = null;
					} else if (next.text === '[') {
						context = _primary;
						_primary = objectIndex(_primary);
					} else if (next.text === '.') {
						context = _primary;
						_primary = fieldAccess(_primary);
					} else {
						throwError("IMPOSSIBLE");
					}
				}
				return _primary;
			}

			function _fieldAccess(object) {
				var field = expect().text;
				var getter = getterFn(field, csp);
				return extend(function(scope, locals, self) {
					return getter(self || object(scope, locals), locals);
				}, {
					assign : function(scope, value, locals) {
						var o = object(scope, locals);
						// in a.b[3].c, when b is null
						if (o == null)
							o = object.assign(scope, {}, locals);
						return setter(o, field, value);
					}
				});
			}

			function _objectIndex(obj) {
				var indexFn = expression();
				consume(']');
				return extend(function(self, locals) {
					var o = obj(self, locals), i = indexFn(self, locals), v, p;
					if (!o)
						return undefined;
					v = o[i];
					if (v && v.then) {
						p = v;
						if (!('$$v' in v)) {
							p.$$v = undefined;
							p.then(function(val) {
								p.$$v = val;
							});
						}
						v = v.$$v;
					}
					return v;
				}, {
					assign : function(self, value, locals) {
						var arr = obj(self, locals), i = indexFn(self, locals);
						// if not found, new array
						if (arr == null)
							arr = obj.assign(self, isString(i) ? {} : []);
						return arr[i] = value;
					}
				});
			}

			function _functionCall(fn, contextGetter) {
				var argsFn = [];
				if (peekToken().text != ')') {
					do {
						argsFn.push(expression());
					} while (expect(','));
				}
				consume(')');
				return function(scope, locals) {
					var args = [], context = contextGetter ? contextGetter(scope, locals) : scope;

					for (var i = 0; i < argsFn.length; i++) {
						args.push(argsFn[i](scope, locals));
					}
					var fnPtr = fn(scope, locals, context) || noop;
					// IE stupidity!
					//return fnPtr.apply ? fnPtr.apply(context, args) : fnPtr(args[0], args[1], args[2], args[3], args[4]);
					return _fastInvoke(fnPtr, context, args);
				};
			}

			// This is used with json.json array declaration
			function arrayDeclaration() {
				var elementFns = [];
				var allConstant = true;
				if (peekToken().text != ']') {
					do {
						var elementFn = expression();
						elementFns.push(elementFn);
						if (!elementFn.constant) {
							allConstant = false;
						}
					} while (expect(','));
				}
				consume(']');
				return extend(function(self, locals) {
					var array = [];
					for (var i = 0; i < elementFns.length; i++) {
						array.push(elementFns[i](self, locals));
					}
					return array;
				}, {
					literal : true,
					constant : allConstant
				});
			}

			function object() {
				var keyValues = [];
				var allConstant = true;
				if (peekToken().text != '}') {
					do {
						var token = expect(), key = token.string || token.text;
						consume(":");
						var value = expression();
						keyValues.push({
							key : key,
							value : value
						});
						if (!value.constant) {
							allConstant = false;
						}
					} while (expect(','));
				}
				consume('}');
				return extend(function(self, locals) {
					var object = {};
					for (var i = 0; i < keyValues.length; i++) {
						var keyValue = keyValues[i];
						object[keyValue.key] = keyValue.value(self, locals);
					}
					return object;
				}, {
					literal : true,
					constant : allConstant
				});
			}

		}

		//*****************************
		// Parser helper functions
		//*****************************

		function setter(obj, path, setValue) {
			var element = path.split('.');
			for (var i = 0; element.length > 1; i++) {
				var key = element.shift();
				var propertyObj = obj[key];
				if (!propertyObj) {
					propertyObj = {};
					obj[key] = propertyObj;
				}
				obj = propertyObj;
			}
			obj[element.shift()] = setValue;
			return setValue;
		}

		var getterFnCache = {};

		/**
		 * Implementation of the "Black Hole" variant from:
		 * - http://jsperf.com/vxjs-parse-getter/4
		 * - http://jsperf.com/path-evaluation-simplified/7
		 */
		function cspSafeGetterFn(key0, key1, key2, key3, key4) {
			return function(scope, locals) {
				var pathVal = (locals && locals.hasOwnProperty(key0)) ? locals : scope, promise;

				if (pathVal === null || pathVal === undefined)
					return pathVal;
				pathVal = pathVal[key0];
				if (pathVal && pathVal.then) {
					if (!("$$v" in pathVal)) {
						promise = pathVal;
						promise.$$v = undefined;
						promise.then(function(val) {
							promise.$$v = val;
						});
					}
					pathVal = pathVal.$$v;
				}
				if (!key1 || pathVal === null || pathVal === undefined)
					return pathVal;
				pathVal = pathVal[key1];
				if (pathVal && pathVal.then) {
					if (!("$$v" in pathVal)) {
						promise = pathVal;
						promise.$$v = undefined;
						promise.then(function(val) {
							promise.$$v = val;
						});
					}
					pathVal = pathVal.$$v;
				}
				if (!key2 || pathVal === null || pathVal === undefined)
					return pathVal;
				pathVal = pathVal[key2];
				if (pathVal && pathVal.then) {
					if (!("$$v" in pathVal)) {
						promise = pathVal;
						promise.$$v = undefined;
						promise.then(function(val) {
							promise.$$v = val;
						});
					}
					pathVal = pathVal.$$v;
				}
				if (!key3 || pathVal === null || pathVal === undefined)
					return pathVal;
				pathVal = pathVal[key3];
				if (pathVal && pathVal.then) {
					if (!("$$v" in pathVal)) {
						promise = pathVal;
						promise.$$v = undefined;
						promise.then(function(val) {
							promise.$$v = val;
						});
					}
					pathVal = pathVal.$$v;
				}
				if (!key4 || pathVal === null || pathVal === undefined)
					return pathVal;
				pathVal = pathVal[key4];
				if (pathVal && pathVal.then) {
					if (!("$$v" in pathVal)) {
						promise = pathVal;
						promise.$$v = undefined;
						promise.then(function(val) {
							promise.$$v = val;
						});
					}
					pathVal = pathVal.$$v;
				}
				return pathVal;
			};
		}

		function getterFn(path, csp) {
			if (getterFnCache.hasOwnProperty(path)) {
				return getterFnCache[path];
			}

			var pathKeys = path.split('.'), pathKeysLength = pathKeys.length, fn;

			if (csp) {
				fn = (pathKeysLength < 6) ? cspSafeGetterFn(pathKeys[0], pathKeys[1], pathKeys[2], pathKeys[3], pathKeys[4]) : function(scope, locals) {
					var i = 0, val;
					do {
						val = cspSafeGetterFn(
						pathKeys[i++], pathKeys[i++], pathKeys[i++], pathKeys[i++], pathKeys[i++]
						)(scope, locals);
						locals = undefined;
						// clear after first iteration
						scope = val;
					} while (i < pathKeysLength);
					return val;
				};
			} else {
				var code = 'var l, fn, p;\n';
				forEach(pathKeys, function(key, index) {
					code += 'if(s === null || s === undefined) return s;\n' + 'l=s;\n' + 's=' + ( index
					// we simply dereference 's' on any .dot notation
					? 's'
					// but if we are first then we check locals first, and if so read it first
					: '((k&&k.hasOwnProperty("' + key + '"))?k:s)') + '["' + key + '"]' + ';\n' + //
					'if (s && s.then) {\n' + ' if (!("$$v" in s)) {\n' + ' p=s;\n' + //
					' p.$$v = undefined;\n' + ' p.then(function(v) {p.$$v=v;});\n' + '}\n' + ' s=s.$$v\n' + '}\n';
				});
				code += 'return s;';
				/*jshint evil:true*/
				fn = new Function('s', 'k', code);
				// s=scope, k=locals
				fn.toString = function() {
					return code;
				};
			}

			return getterFnCache[path] = fn;
		}

		return {
			parser : parser,
			getter : getterFn
		};
	})();

	/////////////////////////////////////
	// JSON
	///////////////////////////////////
	/**
	 * @vxdoc function
	 * @name vx.toJson
	 * @function
	 *
	 * @description
	 * Serializes input into a JSON-formatted string.
	 *
	 * @param {Object|Array|Date|string|number} obj Input to be serialized into JSON.
	 * @param {boolean=} pretty If set to true, the JSON output will contain newlines and whitespace.
	 * @returns {string} Jsonified string representing `obj`.
	 */
	var toJson = (function() {
		return function(obj, pretty) {
			if (window.JSON && window.JSON.stringify)
				return JSON.stringify(obj, toJsonReplacer, pretty ? '  ' : null);
			var buf = [];
			toJsonArray(buf, obj, pretty ? "\n  " : null, []);
			return buf.join('');
		};
		function toJsonReplacer(key, value) {
			var val = value;
			if (/^\$+/.test(key) || 'this' === key) {
				val = undefined;
			} else if (isWindow(value)) {
				val = '$WINDOW';
			} else if (value && document === value) {
				val = '$DOCUMENT';
			} else if (isScope(value)) {
				val = '$SCOPE';
			}
			return val;
		}

		function jsonDateToString(date) {
			if (!date)
				return date;
			var isoString = date.toISOString ? date.toISOString() : '';
			return (isoString.length == 24) ? isoString : padNumber(date.getUTCFullYear(), 4) + '-' + //
			padNumber(date.getUTCMonth() + 1, 2) + '-' + padNumber(date.getUTCDate(), 2) + 'T' + //
			padNumber(date.getUTCHours(), 2) + ':' + padNumber(date.getUTCMinutes(), 2) + ':' + //
			padNumber(date.getUTCSeconds(), 2) + '.' + padNumber(date.getUTCMilliseconds(), 3) + 'Z';
		}

		function quoteUnicode(string, pretty) {
			var chars = ['"'];
			for (var i = 0; i < string.length; i++) {
				var code = string.charCodeAt(i);
				var ch = string.charAt(i);
				switch(ch) {
					case '"':
						chars.push('\\"');
						break;
					case '\\':
						chars.push('\\\\');
						break;
					case '\n':
						chars.push('\\n');
						break;
					case '\f':
						chars.push('\\f');
						break;
					case '\r':
						chars.push( ch = '\\r');
						break;
					case '\t':
						chars.push( ch = '\\t');
						break;
					default:
						if (pretty)
							chars.push(ch);
						else {
							if (32 <= code && code <= 126) {
								chars.push(ch);
							} else {
								var encode = "000" + code.toString(16);
								chars.push("\\u" + encode.substring(encode.length - 4));
							}
						}
				}
			}
			chars.push('"');
			return chars.join('');
		}

		function toJsonArray(buf, obj, pretty, stack) {
			if (isObject(obj)) {
				if (obj === window) {
					buf.push('WINDOW');
					return;
				}
				if (obj === document) {
					buf.push('DOCUMENT');
					return;
				}
				if (includes(stack, obj)) {
					buf.push('RECURSION');
					return;
				}
				stack.push(obj);
			}
			if (obj === null) {
				buf.push('null');
			} else if ( obj instanceof RegExp) {
				buf.push(quoteUnicode(obj.toString(), pretty));
			} else if (isFunction(obj)) {
				return;
			} else if (isBoolean(obj)) {
				buf.push('' + obj);
			} else if (isNumber(obj)) {
				if (isNaN(obj)) {
					buf.push('null');
				} else {
					buf.push('' + obj);
				}
			} else if (isString(obj)) {
				return buf.push(quoteUnicode(obj, pretty));
			} else if (isObject(obj)) {
				if (isArray(obj)) {
					buf.push("[");
					var len = obj.length;
					var sep = false;
					for (var i = 0; i < len; i++) {
						var item = obj[i];
						if (sep)
							buf.push(",");
						if (!( item instanceof RegExp) && (isFunction(item) || isUndefined(item))) {
							buf.push('null');
						} else {
							toJsonArray(buf, item, pretty, stack);
						}
						sep = true;
					}
					buf.push("]");
				} else if (isElement(obj)) {
					// TODO(misko): maybe in dev mode have a better error reporting?
					buf.push('DOM_ELEMENT');
				} else if (isDate(obj)) {
					buf.push(quoteUnicode(jsonDateToString(obj), pretty));
				} else {
					buf.push("{");
					if (pretty)
						buf.push(pretty);
					var comma = false;
					var childPretty = pretty ? pretty + "  " : false;
					var keys = [];
					for (var k in obj) {
						if (k != 'this' && k.substring(0, 1) != '$' && obj.hasOwnProperty(k) && obj[k] !== undefined) {
							keys.push(k);
						}
					}
					keys.sort();
					for (var keyIndex = 0; keyIndex < keys.length; keyIndex++) {
						var key = keys[keyIndex];
						var value = obj[key];
						if (!isFunction(value)) {
							if (comma) {
								buf.push(",");
								if (pretty)
									buf.push(pretty);
							}
							buf.push(quoteUnicode(key, pretty));
							buf.push(":");
							toJsonArray(buf, value, childPretty, stack);
							comma = true;
						}
					}
					buf.push("}");
				}
			}
			if (isObject(obj)) {
				stack.pop();
			}
		}

	})();

	/**
	 * @vxdoc function
	 * @name vx.fromJson
	 * @function
	 *
	 * @description
	 * Deserializes a JSON string.
	 *
	 * @param {string} json JSON string to deserialize.
	 * @returns {Object|Array|Date|string|number} Deserialized thingy.
	 */
	function fromJson(json) {
		if (!isString(json))
			return json;
		if (window.JSON && window.JSON.parse) {
			return JSON.parse(json);
		} else {
			return EXPR.parser(json, true)();
		}
	}

	//////////////////////////////////
	//  JQLite
	//////////////////////////////////

	/**
	 * @vxdoc function
	 * @name vx.element
	 * @function
	 *
	 * @description
	 * Wraps a raw DOM element or HTML string as a [jQuery](http://jquery.com) element.
	 * `vx.element` can be either an alias for [jQuery](http://api.jquery.com/jQuery/) function, if
	 * jQuery is available, or a function that wraps the element or string in VX's jQuery lite
	 * implementation (commonly referred to as jqLite).
	 *
	 * Real jQuery always takes precedence over jqLite, provided it was loaded before `DOMContentLoaded`
	 * event fired.
	 *
	 * jqLite is a tiny, API-compatible subset of jQuery that allows
	 * VX to manipulate the DOM. jqLite implements only the most commonly needed functionality
	 * within a very small footprint, so only a subset of the jQuery API - methods, arguments and
	 * invocation styles - are supported.
	 *
	 * Note: All element references in VX are always wrapped with jQuery or jqLite; they are never
	 * raw DOM references.
	 *
	 * ## VX's jQuery lite provides the following methods:
	 *
	 * - [addClass()](http://api.jquery.com/addClass/)
	 * - [after()](http://api.jquery.com/after/)
	 * - [append()](http://api.jquery.com/append/)
	 * - [attr()](http://api.jquery.com/attr/)
	 * - [bind()](http://api.jquery.com/bind/)
	 * - [children()](http://api.jquery.com/children/)
	 * - [clone()](http://api.jquery.com/clone/)
	 * - [contents()](http://api.jquery.com/contents/)
	 * - [css()](http://api.jquery.com/css/)
	 * - [data()](http://api.jquery.com/data/)
	 * - [eq()](http://api.jquery.com/eq/)
	 * - [find()](http://api.jquery.com/find/) - Limited to lookups by tag name.
	 * - [hasClass()](http://api.jquery.com/hasClass/)
	 * - [html()](http://api.jquery.com/html/)
	 * - [next()](http://api.jquery.com/next/)
	 * - [parent()](http://api.jquery.com/parent/)
	 * - [prepend()](http://api.jquery.com/prepend/)
	 * - [prop()](http://api.jquery.com/prop/)
	 * - [ready()](http://api.jquery.com/ready/)
	 * - [remove()](http://api.jquery.com/remove/)
	 * - [removeAttr()](http://api.jquery.com/removeAttr/)
	 * - [removeClass()](http://api.jquery.com/removeClass/)
	 * - [removeData()](http://api.jquery.com/removeData/)
	 * - [replaceWith()](http://api.jquery.com/replaceWith/)
	 * - [text()](http://api.jquery.com/text/)
	 * - [toggleClass()](http://api.jquery.com/toggleClass/)
	 * - [triggerHandler()](http://api.jquery.com/triggerHandler/) - Passes a dummy event object to handlers.
	 * - [unbind()](http://api.jquery.com/unbind/)
	 * - [val()](http://api.jquery.com/val/)
	 * - [wrap()](http://api.jquery.com/wrap/)
	 *
	 * ## In addition to the above, VX privides additional methods to both jQuery and jQuery lite:
	 *
	 * - `controller(name)` - retrieves the controller of the current element or its parent. By default
	 *   retrieves controller associated with the `vController` directive. If `name` is provided as
	 *   camelCase directive name, then the controller for this directive will be retrieved (e.g.
	 *   `'vModel'`).
	 * - `injector()` - retrieves the injector of the current element or its parent.
	 * - `scope()` - retrieves the {@link api/vx.$rootScope.Scope scope} of the current
	 *   element or its parent.
	 * - `inheritedData()` - same as `data()`, but walks up the DOM until a value is found or the top
	 *   parent element is reached.
	 *
	 * @param {string|DOMElement} element HTML string or DOMElement to be wrapped into jQuery.
	 * @returns {Object} jQuery object.
	 */
	function bindJQuery() {
		if (jqLite) {
			var bindFn = jqLite.fn.bind, attrFn = jqLite.fn.attr;
			extend(jqLite.fn, {
				inheritedData : function(name, value) {
					return jqLiteInheritedData(this, name, value);
				},
				scope : function() {
					return this.inheritedData('$scope');
				},
				injector : function() {
					return this.inheritedData('$injector');
				},
				controller : function(name) {
					return this.inheritedData('$' + (name || 'vController' ) + 'Controller');
				},
				bind : function(name, handler) {
					var proxy = name, fn = handler, target = this[0];
					if (name === 'mouseenter' || name === 'mouseleave') {
						var contains = document.body.contains || document.body.compareDocumentPosition ? function(a, b) {
							var adown = a.nodeType === 9 ? a.documentElement : a, bup = b && b.parentNode;
							return a === bup || !!(bup && bup.nodeType === 1 && (adown.contains ? adown.contains(bup) : a.compareDocumentPosition && a.compareDocumentPosition(bup) & 16
							));
						} : function(a, b) {
							if (b) {
								while (( b = b.parentNode)) {
									if (b === a) {
										return true;
									}
								}
							}
							return false;
						};

						// Refer to jQuery's implementation of mouseenter & mouseleave
						// Read about mouseenter and mouseleave:
						// http://www.quirksmode.org/js/events_mouse.html#link8
						var eventmap = {
							mouseleave : "mouseout",
							mouseenter : "mouseover"
						};
						proxy = eventmap[name];
						fn = function(event) {
							var ret, target = this, related = event.relatedTarget;
							// For mousenter/leave call the handler if related is outside the target.
							// NB: No relatedTarget if the mouse left/entered the browser window
							if (!related || (related !== target && !contains(target, related))) {
								handler(event, name);
							}

						};
					}
					return bindFn.call(this, proxy, fn);
				},
				attr : function(attrName, value) {
					//*** jimmy, fix IE cannot modify 'name' and 'id' of element (eg. <input name='...'>)
					// only for IE 6, 7
					if (value !== undefined && msie < 8 && (attrName == 'name' || attrName == 'id')) {
						/**
						 *ChenLin
						 *  fix SCRIPT5022:DOM Exception
						 */
						var html = jqLite("<input " + attrName + "='" + value + "'/>");
						if (this && this.length > 0)
							this[0].mergeAttributes(html[0], false);
						return this;
					} else
						return value === undefined ? attrFn.call(this, attrName) : attrFn.call(this, attrName, value);
				}
			});
			// Method signature: jqLitePatchRemove(name, dispatchThis, filterElems, getterIfNoArguments)
			jqLitePatchRemove('remove', true, true, false);
			jqLitePatchRemove('empty', false, false, false);
			jqLitePatchRemove('html', false, false, true);
		} else {
			throw vError(20, 'no jQuery found');
		}

		function contains(p, c) {
			return p.contains ? p != c && p.contains(c) : !!(p.compareDocumentPosition(c) & 16);
		}

		function jqLiteInheritedData(element, name, value) {
			// if element is the document object work with the html element instead
			// this makes $(document).scope() possible
			if (element.length && element[0].nodeType == 9) {
				element = element.find('html');
			}

			while (element.length) {
				/*jshint boss:true*/
				if ( value = element.data(name))
					return value;
				element = element.parent();
			}
		}

		/////////////////////////////////////////////
		// jQuery mutation patch
		//
		//  In conjunction with bindJQuery intercepts all jQuery's DOM destruction APIs and fires a
		// $destroy event on all DOM nodes being removed.
		//
		/////////////////////////////////////////////
		function jqLitePatchRemove(name, dispatchThis, filterElems, getterIfNoArguments) {
			var originalJqFn = original(name);
			removePatch.$original = originalJqFn;
			jqLite.fn[name] = removePatch;

			function original(name) {
				var old = jqLite.fn[name];
				return old.$original || old;
			}

			function removePatch(param) {
				/*jshint validthis:true*/
				var list = filterElems && param ? [this.filter(param)] : [this], //
				fireEvent = dispatchThis, set, setIndex, setLength, element, childIndex, childLength, children;

				if (!getterIfNoArguments || param != null) {
					while (list.length) {
						set = list.shift();
						for ( setIndex = 0, setLength = set.length; setIndex < setLength; setIndex++) {
							element = jqLite(set[setIndex]);
							if (fireEvent) {
								if (element.triggerHandler)
									element.triggerHandler('$destroy');
								if (element.unbindAll) {// for zepto and jqmobi
									element.unbindAll();
									if (element.removeData)
										element.removeData();
								}
							} else {
								fireEvent = !fireEvent;
							}
							for ( childIndex = 0, childLength = ( children = element.children()).length; childIndex < childLength; childIndex++) {
								list.push(jqLite(children[childIndex]));
							}
						}
					}
				}

				if (!msie)
					return originalJqFn.apply(this, arguments);

				var i, me = name === 'remove' ? this : this.contents(), olds = [], ret;
				for ( i = 0; i < me.length; i++)
					olds.push(me[i]);

				if (name === 'html')
					ret = original('empty').apply(this);
				else
					ret = originalJqFn.apply(this, arguments);

				for ( i = 0; i < olds.length; i++)
					IE_GC(olds[i]);

				return name === 'html' ? originalJqFn.apply(ret, arguments) : ret;
			}

		}

	}

	function jqLiteClone(element) {
		if (element && element.cloneNode) {
			return element.cloneNode(true);
		}
		var el;
		for (var i = 0; i < element.length; i++) {
			if (el === undefined) {
				el = jqLite(jqLiteClone(element[i]));
			} else {
				el.push(jqLiteClone(element[i]));
			}
		}
		return el === undefined ? element : el;
	}

	/**
	 * Parses an escaped url query string into key-value pairs.
	 * @returns Object.<(string|boolean)>
	 */
	function parseKeyValue(/**string*/keyValue) {
		var obj = {}, key_value, key;
		vx.forEach((keyValue || "").split('&'), function(keyValue) {
			if (keyValue) {
				key_value = keyValue.split('=');
				key = decodeURIComponent(key_value[0]);
				obj[key] = isDefined(key_value[1]) ? decodeURIComponent(key_value[1]) : true;
			}
		});
		return obj;
	}

	function toKeyValue(obj) {
		var parts = [];
		vx.forEach(obj, function(value, key) {
			parts.push(encodeUriQuery(key, true) + (value === true ? '' : '=' + encodeUriQuery(value, true)));
		});
		return parts.length ? parts.join('&') : '';
	}

	/**
	 * We need our custom method because encodeURIComponent is too aggressive and doesn't follow
	 * http://www.ietf.org/rfc/rfc3986.txt with regards to the character set (pchar) allowed in path
	 * segments:
	 *    segment       = *pchar
	 *    pchar         = unreserved / pct-encoded / sub-delims / ":" / "@"
	 *    pct-encoded   = "%" HEXDIG HEXDIG
	 *    unreserved    = ALPHA / DIGIT / "-" / "." / "_" / "~"
	 *    sub-delims    = "!" / "$" / "&" / "'" / "(" / ")"
	 *                     / "*" / "+" / "," / ";" / "="
	 */
	function encodeUriSegment(val) {
		return encodeUriQuery(val, true).replace(/%26/gi, '&').replace(/%3D/gi, '=').replace(/%2B/gi, '+');
	}

	/**
	 * This method is intended for encoding *key* or *value* parts of query component. We need a custom
	 * method because encodeURIComponent is too aggressive and encodes stuff that doesn't have to be
	 * encoded per http://tools.ietf.org/html/rfc3986:
	 *    query       = *( pchar / "/" / "?" )
	 *    pchar         = unreserved / pct-encoded / sub-delims / ":" / "@"
	 *    unreserved    = ALPHA / DIGIT / "-" / "." / "_" / "~"
	 *    pct-encoded   = "%" HEXDIG HEXDIG
	 *    sub-delims    = "!" / "$" / "&" / "'" / "(" / ")"
	 *                     / "*" / "+" / "," / ";" / "="
	 */
	function encodeUriQuery(val, pctEncodeSpaces) {
		return encodeURIComponent(val).replace(/%40/gi, '@').replace(/%3A/gi, ':').replace(/%24/g, '$')//
		.replace(/%2C/gi, ',').replace(/%20/g, ( pctEncodeSpaces ? '%20' : '+'));
	}

	///////////////////////////////
	// vx config
	//////////////////////////////

	/**
	 * @vxdoc property
	 * @name vx.version
	 * @description
	 * An object that contains information about the current VXJS version. This object has the
	 * following properties:
	 *
	 * - `full` – `{string}` – Full version string, such as "0.9.18".
	 * - `major` – `{number}` – Major version number, such as "0".
	 * - `minor` – `{number}` – Minor version number, such as "9".
	 * - `dot` – `{number}` – Dot version number, such as "18".
	 * - `codeName` – `{string}` – Code name of the release, such as "jiggling-armfat".
	 */
	var version = {
		full : '1.1.5', // all of these placeholder strings will be replaced by rake's
		major : 1, // compile task
		minor : 1,
		dot : 5,
		codeName : 'Venus UltraView - (VX)'
	};

	function vxSetup(vx) {
		bindJQuery();
		extend(vx, {
			'cleanupClosure' : cleanupClosure,
			'vError' : vError,
			'formatError' : formatError,
			'$TIMESTAMP' : now(),
			'$UUID' : uuid(),
			'define' : define,
			'msie' : msie, //
			'URL' : URL,
			'uid' : function() {
				return nextUid(VID);
			},
			'uuid' : uuid,
			'now' : now,
			'version' : version,
			'module' : moduler(),
			'init' : vxInit, //
			'bootstrap' : bootstrap,
			'injector' : createInjector,
			'element' : jqLite,

			'copy' : copy,
			//'shallowCopy' : shallowCopy,
			'equals' : equals,
			'extend' : extend,
			'inherit' : inherit,
			'bind' : bind,
			'forEach' : forEach,
			'noop' : noop,
			'identity' : identity,
			'valueFn' : valueFn, //

			'toJson' : toJson,
			'fromJson' : fromJson,

			'isUndefined' : isUndefined,
			'isDefined' : isDefined,
			'isEmpty' : isEmpty,
			'isFile' : isFile,
			'isBoolean' : isBoolean,
			'toBoolean' : toBoolean,
			'isString' : isString,
			'isFunction' : isFunction,
			'isObject' : isObject,
			'isNumber' : isNumber,
			'isElement' : isElement,
			'isArray' : isArray,
			'isDate' : isDate,
			'isRegExp' : isRegExp,
			'isWindow' : isWindow,
			'isScope' : isScope,

			'lowercase' : lowercase,
			'uppercase' : uppercase,
			'trim' : trim,
			'includes' : includes,
			'indexOf' : indexOf,
			//'concat' : concat,

			'parseKeyValue' : parseKeyValue,
			'toKeyValue' : toKeyValue,
			'encodeUriSegment' : encodeUriSegment, //
			'encodeUriQuery' : encodeUriQuery,
			'_nodeName' : _nodeName,

			'callbacks' : {//XXX by jsonp
				counter : 0
			}
		});
		// defined core modules
		vx.module('vLocale', []).value('$locale', {});
		vx.module('v', ['vLocale']);
		// init services, filters, directives
		vxSetupServices();
		vxSetupFilters();
		vxSetupDirectives();
	}

	/**
	 * @vxdoc interface
	 * @name vx.Module
	 * @description
	 *
	 * Interface for configuring vx {@link vx.module modules}.
	 */
	function moduler() {
		function ensure(obj, name, factory) {
			return obj[name] || (obj[name] = factory());
		}

		/** @type {Object.<string, vx.Module>} */
		var modules = {};
		/**
		 * @vxdoc function
		 * @name vx.module
		 * @description
		 *
		 * The `vx.module` is a global place for creating and registering VX modules. All
		 * modules (vx core or 3rd party) that should be available to an application must be
		 * registered using this mechanism.
		 *
		 *
		 * # Module
		 *
		 * A module is a collocation of services, directives, filters, and configuration information. Module
		 * is used to configure the {@link AUTO.$injector $injector}.
		 *
		 * <pre>
		 * // Create a new module
		 * var myModule = vx.module('myModule', []);
		 *
		 * // register a new service
		 * myModule.value('appName', 'MyCoolApp');
		 *
		 * // configure existing services inside initialization blocks.
		 * myModule.config(function($locationProvider) {
		 *   // Configure existing providers
		 *   $locationProvider.hashPrefix('!');
		 * });
		 * </pre>
		 *
		 * Then you can create an injector and load your modules like this:
		 *
		 * <pre>
		 * var injector = vx.injector(['v', 'MyModule'])
		 * </pre>
		 *
		 * However it's more likely that you'll just use
		 * {@link vx.directive:vApp vApp} or
		 * {@link vx.bootstrap} to simplify this process for you.
		 *
		 * @param {!string} name The name of the module to create or retrieve.
		 * @param {Array.<string>=} requires If specified then new module is being created. If unspecified then the
		 *        the module is being retrieved for further configuration.
		 * @param {Function} configFn Optional configuration function for the module. Same as
		 *        {@link vx.Module#config Module#config()}.
		 * @returns {module} new module with the {@link vx.Module} api.
		 */
		return function module(name, requires, configFn) {
			if (requires && modules.hasOwnProperty(name)) {
				modules[name] = null;
			}

			return ensure(modules, name, function() {
				if (!requires) {
					throw vError(21, "Module '{0}' is not available! You either misspelled the module name or forgot to load it.", name);
				}

				/** @type {!Array.<Array.<*>>} */
				var invokeQueue = [];
				/** @type {!Array.<Function>} */
				var runBlocks = [];
				var config = invokeLater('$injector', 'invoke');
				/** @type {vx.Module} */
				var moduleInstance = {
					// Private state
					_invokeQueue : invokeQueue,
					_runBlocks : runBlocks,

					/**
					 * @vxdoc property
					 * @name vx.Module#requires
					 * @propertyOf vx.Module
					 * @returns {Array.<string>} List of module names which must be loaded before this module.
					 * @description
					 * Holds the list of modules which the injector will load before the current module is loaded.
					 */
					requires : requires,

					/**
					 * @vxdoc property
					 * @name vx.Module#name
					 * @propertyOf vx.Module
					 * @returns {string} Name of the module.
					 * @description
					 */
					name : name,

					/**
					 * @vxdoc method
					 * @name vx.Module#provider
					 * @methodOf vx.Module
					 * @param {string} name service name
					 * @param {Function} providerType Construction function for creating new instance of the service.
					 * @description
					 * See {@link AUTO.$provide#provider $provide.provider()}.
					 */
					provider : invokeLater('$provide', 'provider'),

					/**
					 * @vxdoc method
					 * @name vx.Module#factory
					 * @methodOf vx.Module
					 * @param {string} name service name
					 * @param {Function} providerFunction Function for creating new instance of the service.
					 * @description
					 * See {@link AUTO.$provide#factory $provide.factory()}.
					 */
					factory : invokeLater('$provide', 'factory'),

					/**
					 * @vxdoc method
					 * @name vx.Module#service
					 * @methodOf vx.Module
					 * @param {string} name service name
					 * @param {Function} constructor A constructor function that will be instantiated.
					 * @description
					 * See {@link AUTO.$provide#service $provide.service()}.
					 */
					service : invokeLater('$provide', 'service'),

					/**
					 * @vxdoc method
					 * @name vx.Module#value
					 * @methodOf vx.Module
					 * @param {string} name service name
					 * @param {*} object Service instance object.
					 * @description
					 * See {@link AUTO.$provide#value $provide.value()}.
					 */
					value : invokeLater('$provide', 'value'),

					/**
					 * @vxdoc method
					 * @name vx.Module#constant
					 * @methodOf vx.Module
					 * @param {string} name constant name
					 * @param {*} object Constant value.
					 * @description
					 * Because the constant are fixed, they get applied before other provide methods.
					 * See {@link AUTO.$provide#constant $provide.constant()}.
					 */
					constant : invokeLater('$provide', 'constant', 'unshift'),

					/**
					 * @vxdoc method
					 * @name vx.Module#animation
					 * @methodOf vx.Module
					 * @param {string} name animation name
					 * @param {Function} animationFactory Factory function for creating new instance of an animation.
					 * @description
					 *
					 * Defines an animation hook that can be later used with {@link vx.directive:vAnimate vAnimate}
					 * alongside {@link vx.directive:vAnimate#Description common vx directives} as well as custom directives.
					 * <pre>
					 * module.animation('animation-name', function($inject1, $inject2) {
					 *   return {
					 *     //this gets called in preparation to setup an animation
					 *     setup : function(element) { ... },
					 *
					 *     //this gets called once the animation is run
					 *     start : function(element, done, memo) { ... }
					 *   }
					 * })
					 * </pre>
					 *
					 * See {@link vx.$animationProvider#register $animationProvider.register()} and
					 * {@link vx.directive:vAnimate vAnimate} for more information.
					 */
					animation : invokeLater('$animationProvider', 'register'),

					/**
					 * @vxdoc method
					 * @name vx.Module#filter
					 * @methodOf vx.Module
					 * @param {string} name Filter name.
					 * @param {Function} filterFactory Factory function for creating new instance of filter.
					 * @description
					 * See {@link vx.$filterProvider#register $filterProvider.register()}.
					 */
					filter : invokeLater('$filterProvider', 'register'),

					/**
					 * @vxdoc method
					 * @name vx.Module#controller
					 * @methodOf vx.Module
					 * @param {string} name Controller name.
					 * @param {Function} constructor Controller constructor function.
					 * @description
					 * See {@link vx.$controllerProvider#register $controllerProvider.register()}.
					 */
					controller : invokeLater('$controllerProvider', 'register'),

					/**
					 * @vxdoc method
					 * @name vx.Module#directive
					 * @methodOf vx.Module
					 * @param {string} name directive name
					 * @param {Function} directiveFactory Factory function for creating new instance of
					 * directives.
					 * @description
					 * See {@link vx.$compileProvider#directive $compileProvider.directive()}.
					 */
					directive : invokeLater('$compileProvider', 'directive'),

					/**
					 * @vxdoc method
					 * @name vx.Module#config
					 * @methodOf vx.Module
					 * @param {Function} configFn Execute this function on module load. Useful for service
					 *    configuration.
					 * @description
					 * Use this method to register work which needs to be performed on module loading.
					 */
					config : config,

					/**
					 * @vxdoc method
					 * @name vx.Module#run
					 * @methodOf vx.Module
					 * @param {Function} initializationFn Execute this function after injector creation.
					 *    Useful for application initialization.
					 * @description
					 * Use this method to register work which should be performed when the injector is done
					 * loading all modules.
					 */
					run : function(block) {
						runBlocks.push(block);
						return this;
					}
				};
				if (configFn) {
					config(configFn);
				}
				return moduleInstance;

				/**
				 * @param {string} provider
				 * @param {string} method
				 * @param {String=} insertMethod
				 * @returns {vx.Module}
				 */
				function invokeLater(provider, method, insertMethod) {
					return function() {
						invokeQueue[insertMethod || 'push']([provider, method, arguments]);
						return moduleInstance;
					};
				}

			});
		};
	}

	////////////////////////////////////
	//  vx initialization
	////////////////////////////////////

	/**
	 * @vxdoc directive
	 * @name vx.directive:vApp
	 *
	 * @element ANY
	 * @param {vx.Module} vApp an optional application
	 *   {@link vx.module module} name to load.
	 *
	 * @description
	 *
	 * Use this directive to auto-bootstrap an application. Only
	 * one directive can be used per HTML document. The directive
	 * designates the root of the application and is typically placed
	 * at the root of the page.
	 *
	 * In the example below if the `vApp` directive would not be placed
	 * on the `html` element then the document would not be compiled
	 * and the `{{ 1+2 }}` would not be resolved to `3`.
	 *
	 * `vApp` is the easiest way to bootstrap an application.
	 *
	 <doc:example>
	 <doc:source>
	 I can add: 1 + 2 =  {{ 1+2 }}
	 </doc:source>
	 </doc:example>
	 *
	 */
	function vxInit(element, bootstrap) {
		var elements = [element], appElement, module, names = ['v:app', 'v-app', 'x-v-app', 'data-v-app'], //
		V_APP_CLASS_REGEXP = /\sv[:\-]app(:\s*([\w\d_]+);?)?\s/;

		function append(element) {
			if (element)
				elements.push(element);
		}

		forEach(names, function(name) {
			names[name] = true;
			append(document.getElementById(name));
			name = name.replace(':', '\\:');
			forEach(jqLite(element).find('.' + name), append);
			forEach(jqLite(element).find('.' + name + '\\:'), append);
			forEach(jqLite(element).find('[' + name + ']'), append);
		});
		forEach(elements, function(element) {
			if (!appElement) {
				var className = ' ' + element.className + ' ';
				var match = V_APP_CLASS_REGEXP.exec(className);
				if (match) {
					appElement = element;
					module = (match[2] || '').replace(/\s+/g, ',');
				} else {
					forEach(element.attributes, function(attr) {
						if (attr.specified && !appElement && names[attr.name]) {
							appElement = element;
							module = attr.value;
						}
					});
				}
			}
		});
		if (appElement) {
			bootstrap(appElement, module ? [module] : []);
		}
	}

	/**
	 * @vxdoc function
	 * @name vx.bootstrap
	 * @description
	 * Use this function to manually start up vx application.
	 *
	 * See: {@link guide/bootstrap Bootstrap}
	 *
	 * @param {Element} element DOM element which is the root of vx application.
	 * @param {Array<String|Function>=} modules an array of module declarations. See: {@link vx.module modules}
	 * @returns {AUTO.$injector} Returns the newly created injector for this app.
	 */
	function bootstrap(element, modules) {
		var resumeBootstrapInternal = function() {
			modules = modules || [];
			modules.unshift(['$provide',
			function($provide) {
				$provide.value('$rootElement', jqLite(element));
			}]);
			modules.unshift('v');
			var injector = createInjector(modules);
			injector.invoke(['$rootScope', '$rootElement', '$compile', '$injector', '$animator',
			function(scope, element, compile, injector, animator) {
				scope.$apply(function() {
					element.data('$injector', injector);
					compile(element)(scope);
				}, 'v-app');
				animator.enabled(true);
			}]);
			return injector;
		};

		var V_DEFER_BOOTSTRAP = /^V_DEFER_BOOTSTRAP!/;
		var defer = element.getAttributeNode('defer') !== null || (window && V_DEFER_BOOTSTRAP.test(window.name));

		if (!defer) {
			return resumeBootstrapInternal();
		}

		window.name = window.name.replace(V_DEFER_BOOTSTRAP, '');
		vx.resumeBootstrap = function(extraModules) {
			forEach(extraModules, function(module) {
				modules.push(module);
			});
			resumeBootstrapInternal();
		};
	}

	/**
	 * @vxdoc function
	 * @name vx.injector
	 * @function
	 *
	 * @description
	 * Creates an injector function that can be used for retrieving services as well as for
	 * dependency injection (see {@link guide/di dependency injection}).
	 *

	 * @param {Array.<string|Function>} modules A list of module functions or their aliases. See
	 *        {@link vx.module}. The `v` module must be explicitly added.
	 * @returns {function()} Injector function. See {@link AUTO.$injector $injector}.
	 *
	 * @example
	 * Typical usage
	 * <pre>
	 *   // create an injector
	 *   var $injector = vx.injector(['v']);
	 *
	 *   // use the injector to kick off your application
	 *   // use the type inference to auto inject arguments, or use implicit injection
	 *   $injector.invoke(function($rootScope, $compile, $document){
	 *     $compile($document)($rootScope);
	 *     $rootScope.$digest();
	 *   });
	 * </pre>
	 */

	/**
	 * @vxdoc object
	 * @name AUTO.$injector
	 * @function
	 *
	 * @description
	 *
	 * `$injector` is used to retrieve object instances as defined by
	 * {@link AUTO.$provide provider}, instantiate types, invoke methods,
	 * and load modules.
	 *
	 * The following always holds true:
	 *
	 * <pre>
	 *   var $injector = vx.injector();
	 *   expect($injector.get('$injector')).toBe($injector);
	 *   expect($injector.invoke(function($injector){
	 *     return $injector;
	 *   }).toBe($injector);
	 * </pre>
	 *
	 * # Injection Function Annotation
	 *
	 * JavaScript does not have annotations, and annotations are needed for dependency injection. The
	 * following are all valid ways of annotating function with injection arguments and are equivalent.
	 *
	 * <pre>
	 *   // inferred (only works if code not minified/obfuscated)
	 *   $injector.invoke(function(serviceA){});
	 *
	 *   // annotated
	 *   function explicit(serviceA) {};
	 *   explicit.$inject = ['serviceA'];
	 *   $injector.invoke(explicit);
	 *
	 *   // inline
	 *   $injector.invoke(['serviceA', function(serviceA){}]);
	 * </pre>
	 *
	 * ## Inference
	 *
	 * In JavaScript calling `toString()` on a function returns the function definition. The definition can then be
	 * parsed and the function arguments can be extracted. *NOTE:* This does not work with minification, and obfuscation
	 * tools since these tools change the argument names.
	 *
	 * ## `$inject` Annotation
	 * By adding a `$inject` property onto a function the injection parameters can be specified.
	 *
	 * ## Inline
	 * As an array of injection names, where the last item in the array is the function to call.
	 */
	function createInjector(modulesToLoad) {
		var INSTANTIATING = {}, providerSuffix = 'Provider', path = [], loadedModules = new HashMap(),
		//XXX provider space, providerInjector could access only by module's config(...)
		pending = [], providerCache = {
			/**
			 * @vxdoc object
			 * @name AUTO.$provide
			 *
			 * @description
			 *
			 * Use `$provide` to register new providers with the `$injector`. The providers are the factories for the instance.
			 * The providers share the same name as the instance they create with `Provider` suffixed to them.
			 *
			 * A provider is an object with a `$get()` method. The injector calls the `$get` method to create a new instance of
			 * a service. The Provider can have additional methods which would allow for configuration of the provider.
			 *
			 * <pre>
			 *   function GreetProvider() {
			 *     var salutation = 'Hello';
			 *
			 *     this.salutation = function(text) {
			 *       salutation = text;
			 *     };
			 *
			 *     this.$get = function() {
			 *       return function (name) {
			 *         return salutation + ' ' + name + '!';
			 *       };
			 *     };
			 *   }
			 *
			 *   describe('Greeter', function(){
			 *
			 *     beforeEach(module(function($provide) {
			 *       $provide.provider('greet', GreetProvider);
			 *     }));
			 *
			 *     it('should greet', inject(function(greet) {
			 *       expect(greet('vx')).toEqual('Hello vx!');
			 *     }));
			 *
			 *     it('should allow configuration of salutation', function() {
			 *       module(function(greetProvider) {
			 *         greetProvider.salutation('Ahoj');
			 *       });
			 *       inject(function(greet) {
			 *         expect(greet('vx')).toEqual('Ahoj vx!');
			 *       });
			 *     });
			 *
			 *   });
			 * </pre>
			 */
			$provide : {
				provider : supportObject(provider),
				factory : supportObject(factory),
				service : supportObject(service),
				value : supportObject(value),
				constant : supportObject(constant),
				decorator : decorator
			}
		}, providerInjector = (providerCache.$injector = createInternalInjector(providerCache, function() {
			throw vError(22, "Unknown provider: {0}", path.join(' <- '));
		})),
		//XXX instance space, instanceInjector could get by '$injector'
		instanceCache = {}, instanceInjector = (instanceCache.$injector = createInternalInjector(instanceCache, function(servicename) {
			var provider = providerInjector.get(servicename + providerSuffix);
			var instance = instanceInjector.invoke(provider.$get, provider);
			return instance;
		}));
		// XXX let provide know all Providers for trace
		providerCache.$provide.$providers = providerCache;

		forEach(loadModules(modulesToLoad), function(fn) {
			instanceInjector.invoke(fn || noop);
		});
		return instanceInjector;

		//****************************
		// $provider
		//***************************

		/**
		 * @vxdoc method
		 * @name AUTO.$provide#provider
		 * @methodOf AUTO.$provide
		 * @description
		 *
		 * Register a provider for a service. The providers can be retrieved and can have additional configuration methods.
		 *
		 * @param {string} name The name of the instance. NOTE: the provider will be available under `name + 'Provider'` key.
		 * @param {(Object|function())} provider If the provider is:
		 *
		 *   - `Object`: then it should have a `$get` method. The `$get` method will be invoked using
		 *               {@link AUTO.$injector#invoke $injector.invoke()} when an instance needs to be created.
		 *   - `Constructor`: a new instance of the provider will be created using
		 *               {@link AUTO.$injector#instantiate $injector.instantiate()}, then treated as `object`.
		 *
		 * @returns {Object} registered provider instance
		 */

		function provider(name, provider_) {
			if (isFunction(provider_) || isArray(provider_)) {
				provider_ = providerInjector.instantiate(provider_);
			}
			if (!provider_.$get) {
				throw vError(23, "Provider '{0}' must define $get factory method.", name);
			}
			return providerCache[name + providerSuffix] = provider_;
		}

		/**
		 * @vxdoc method
		 * @name AUTO.$provide#factory
		 * @methodOf AUTO.$provide
		 * @description
		 *
		 * A short hand for configuring services if only `$get` method is required.
		 *
		 * @param {string} name The name of the instance.
		 * @param {function()} $getFn The $getFn for the instance creation. Internally this is a short hand for
		 * `$provide.provider(name, {$get: $getFn})`.
		 * @returns {Object} registered provider instance
		 */
		function factory(name, factoryFn) {
			return provider(name, {
				$get : factoryFn
			});
		}

		/**
		 * @vxdoc method
		 * @name AUTO.$provide#service
		 * @methodOf AUTO.$provide
		 * @description
		 *
		 * A short hand for registering service of given class.
		 *
		 * @param {string} name The name of the instance.
		 * @param {Function} constructor A class (constructor function) that will be instantiated.
		 * @returns {Object} registered provider instance
		 */
		function service(name, constructor) {
			return factory(name, ['$injector',
			function($injector) {
				return $injector.instantiate(constructor);
			}]);

		}

		/**
		 * @vxdoc method
		 * @name AUTO.$provide#value
		 * @methodOf AUTO.$provide
		 * @description
		 *
		 * A short hand for configuring services if the `$get` method is a constant.
		 *
		 * @param {string} name The name of the instance.
		 * @param {*} value The value.
		 * @returns {Object} registered provider instance
		 */
		function value(name, val) {
			return factory(name, valueFn(val));
		}

		/**
		 * @vxdoc method
		 * @name AUTO.$provide#constant
		 * @methodOf AUTO.$provide
		 * @description
		 *
		 * A constant value, but unlike {@link AUTO.$provide#value value} it can be injected
		 * into configuration function (other modules) and it is not interceptable by
		 * {@link AUTO.$provide#decorator decorator}.
		 *
		 * @param {string} name The name of the constant.
		 * @param {*} value The constant value.
		 * @returns {Object} registered instance
		 */
		function constant(name, value) {
			providerCache[name] = value;
			instanceCache[name] = value;
		}

		/**
		 * @vxdoc method
		 * @name AUTO.$provide#decorator
		 * @methodOf AUTO.$provide
		 * @description
		 *
		 * Decoration of service, allows the decorator to intercept the service instance creation. The
		 * returned instance may be the original instance, or a new instance which delegates to the
		 * original instance.
		 *
		 * @param {string} name The name of the service to decorate.
		 * @param {function()} decorator This function will be invoked when the service needs to be
		 *    instantiated. The function is called using the {@link AUTO.$injector#invoke
		 *    injector.invoke} method and is therefore fully injectable. Local injection arguments:
		 *
		 *    * `$delegate` - The original service instance, which can be monkey patched, configured,
		 *      decorated or delegated to.
		 */
		function decorator(serviceName, decorFn) {
			var origProvider = providerInjector.get(serviceName + providerSuffix), orig$get = origProvider.$get;
			origProvider.$get = function() {
				var origInstance = instanceInjector.invoke(orig$get, origProvider);
				return instanceInjector.invoke(decorFn, null, {
					$delegate : origInstance
				});
			};
		}

		//***************************
		// Module Loading
		//***************************
		function loadModules(modulesToLoad) {
			var runBlocks = [];
			forEach(modulesToLoad, function(module) {
				if (loadedModules.get(module))
					return;
				loadedModules.put(module, true);
				if (isString(module)) {
					var moduleFn = vx.module(module);
					runBlocks = runBlocks.concat(loadModules(moduleFn.requires)).concat(moduleFn._runBlocks);
					try {
						for (var invokeQueue = moduleFn._invokeQueue, i = 0, ii = invokeQueue.length; i < ii; i++) {
							var invokeArgs = invokeQueue[i], provider = providerInjector.get(invokeArgs[0]);
							provider[invokeArgs[1]].apply(provider, invokeArgs[2]);
						}
					} catch (e) {
						if (e.message)
							e.message += ' from ' + module + ', args: ' + toJson(invokeArgs);
						throw e;
					}
				} else if (isFunction(module)) {
					try {
						runBlocks.push(providerInjector.invoke(module));
					} catch (e) {
						if (e.message)
							e.message += ' from ' + module;
						throw e;
					}
				} else if (isArray(module)) {
					try {
						runBlocks.push(providerInjector.invoke(module));
					} catch (e) {
						if (e.message)
							e.message += ' from ' + String(module[module.length - 1]);
						throw e;
					}
				} else {
					assertArgFn(module, 'module');
				}
			});
			return runBlocks;
		}

		//**************************
		// internal Injector
		//**************************

		function createInternalInjector(cache, factory) {

			/**
			 * @vxdoc method
			 * @name AUTO.$injector#annotate
			 * @methodOf AUTO.$injector
			 *
			 * @description
			 * Returns an array of service names which the function is requesting for injection. This API is used by the injector
			 * to determine which services need to be injected into the function when the function is invoked. There are three
			 * ways in which the function can be annotated with the needed dependencies.
			 *
			 * # Argument names
			 *
			 * The simplest form is to extract the dependencies from the arguments of the function. This is done by converting
			 * the function into a string using `toString()` method and extracting the argument names.
			 * <pre>
			 *   // Given
			 *   function MyController($scope, $route) {
			 *     // ...
			 *   }
			 *
			 *   // Then
			 *   expect(injector.annotate(MyController)).toEqual(['$scope', '$route']);
			 * </pre>
			 *
			 * This method does not work with code minfication / obfuscation. For this reason the following annotation strategies
			 * are supported.
			 *
			 * # The `$inject` property
			 *
			 * If a function has an `$inject` property and its value is an array of strings, then the strings represent names of
			 * services to be injected into the function.
			 * <pre>
			 *   // Given
			 *   var MyController = function(obfuscatedScope, obfuscatedRoute) {
			 *     // ...
			 *   }
			 *   // Define function dependencies
			 *   MyController.$inject = ['$scope', '$route'];
			 *
			 *   // Then
			 *   expect(injector.annotate(MyController)).toEqual(['$scope', '$route']);
			 * </pre>
			 *
			 * # The array notation
			 *
			 * It is often desirable to inline Injected functions and that's when setting the `$inject` property is very
			 * inconvenient. In these situations using the array notation to specify the dependencies in a way that survives
			 * minification is a better choice:
			 *
			 * <pre>
			 *   // We wish to write this (not minification / obfuscation safe)
			 *   injector.invoke(function($compile, $rootScope) {
			 *     // ...
			 *   });
			 *
			 *   // We are forced to write break inlining
			 *   var tmpFn = function(obfuscatedCompile, obfuscatedRootScope) {
			 *     // ...
			 *   };
			 *   tmpFn.$inject = ['$compile', '$rootScope'];
			 *   injector.invoke(tmpFn);
			 *
			 *   // To better support inline function the inline annotation is supported
			 *   injector.invoke(['$compile', '$rootScope', function(obfCompile, obfRootScope) {
			 *     // ...
			 *   }]);
			 *
			 *   // Therefore
			 *   expect(injector.annotate(
			 *      ['$compile', '$rootScope', function(obfus_$compile, obfus_$rootScope) {}])
			 *    ).toEqual(['$compile', '$rootScope']);
			 * </pre>
			 *
			 * @param {function|Array.<string|Function>} fn Function for which dependent service names need to be retrieved as described
			 *   above.
			 *
			 * @returns {Array.<string>} The names of the services which the function requires.
			 */
			var FN_ARGS = /^function\s*[^\(]*\(\s*([^\)]*)\)/m;
			var FN_ARG_SPLIT = /,/;
			var FN_ARG = /^\s*(_?)(\S+?)\1\s*$/;
			var STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg;

			function annotate(fn) {
				var $inject, fnText, argDecl, last;

				if ( typeof fn == 'function') {
					if (!( $inject = fn.$inject)) {
						$inject = [];
						fnText = fn.toString().replace(STRIP_COMMENTS, '');
						argDecl = fnText.match(FN_ARGS);
						forEach(argDecl[1].split(FN_ARG_SPLIT), function(arg) {
							arg.replace(FN_ARG, function(all, underscore, name) {
								$inject.push(name);
							});
						});
						fn.$inject = $inject;
					}
				} else if (isArray(fn)) {
					last = fn.length - 1;
					assertArgFn(fn[last], 'fn');
					$inject = fn.slice(0, last);
				} else {
					assertArgFn(fn, 'fn', true);
				}
				return $inject;
			}

			/**
			 * @vxdoc method
			 * @name AUTO.$injector#get
			 * @methodOf AUTO.$injector
			 *
			 * @description
			 * Return an instance of the service.
			 *
			 * @param {string} name The name of the instance to retrieve.
			 * @return {*} The instance.
			 */
			function getService(serviceName) {
				if (cache.hasOwnProperty(serviceName)) {
					if (cache[serviceName] === INSTANTIATING) {
						throw vError(24, 'Circular dependency found: {0}', path.join(' <- '));
					}
					return cache[serviceName];
				} else {
					try {
						path.unshift(serviceName);
						cache[serviceName] = INSTANTIATING;
						return cache[serviceName] = factory(serviceName);
					} finally {
						path.shift();
						if (path.length === 0 && pending.length > 0) {
							// when root service, fire all post Construct
							while (pending.length > 0) {
								var fn = pending.shift();
								fn();
							}
						}
					}
				}
			}

			/**
			 * @vxdoc method
			 * @name AUTO.$injector#invoke
			 * @methodOf AUTO.$injector
			 *
			 * @description
			 * Invoke the method and supply the method arguments from the `$injector`.
			 *
			 * @param {!function} fn The function to invoke. The function arguments come form the function annotation.
			 * @param {Object=} self The `this` for the invoked method.
			 * @param {Object=} locals Optional object. If preset then any argument names are read from this object first, before
			 *   the `$injector` is consulted.
			 * @returns {*} the value returned by the invoked `fn` function.
			 */
			function invoke(fn, self, locals) {
				var args = [], $inject = annotate(fn), length, i, key;
				var $remote, $http;

				for ( i = 0, length = $inject.length; i < length; i++) {
					key = $inject[i];
					if ( typeof key !== 'string') {
						throw vError(25, 'Incorrect injection token! Expected service name as string, got {0}', key);
					}
					if (locals && locals.$element && (key === '$remote' || key === '$http')) {
						if (!$remote) {
							var $$remote = getService('$$remote');
							injectRemote(locals.$element, locals, '$remote.', false, $$remote);
							$remote = locals.$remote;
							$http = $remote.$http();
						}
						args.push(key === '$http' ? $http : $remote);
					} else
						args.push(locals && locals.hasOwnProperty(key) ? locals[key] : getService(key));
				}
				if (!fn.$inject) {
					// this means that we must be an array.
					fn = fn[length];
				}
				return _fastInvoke(fn, self, args);
			}

			/**
			 * @vxdoc method
			 * @name AUTO.$injector#instantiate
			 * @methodOf AUTO.$injector
			 * @description
			 * Create a new instance of JS type. The method takes a constructor function invokes the new operator and supplies
			 * all of the arguments to the constructor function as specified by the constructor annotation.
			 *
			 * @param {function} Type Annotated constructor function.
			 * @param {Object=} locals Optional object. If preset then any argument names are read from this object first, before
			 *   the `$injector` is consulted.
			 * @returns {Object} new instance of `Type`.
			 */
			function instantiate(Type, locals) {
				var Constructor = function() {
				}, instance, returnedValue;

				// Check if Type is annotated and use just the given function at n-1 as parameter
				// e.g. someModule.factory('greeter', ['$window', function(renamed$window) {}]);
				Constructor.prototype = (isArray(Type) ? Type[Type.length - 1] : Type).prototype;
				instance = new Constructor();
				returnedValue = invoke(Type, instance, locals);
				return isObject(returnedValue) ? returnedValue : instance;
			}

			/**
			 * @vxdoc method
			 * @name AUTO.$injector#has
			 * @methodOf AUTO.$injector
			 *
			 * @description
			 * Allows the user to query if the particular service exist.
			 *
			 * @param {string} Name of the service to query.
			 * @returns {boolean} returns true if injector has given service.
			 */
			function has(name) {
				return providerCache.hasOwnProperty(name + providerSuffix) || cache.hasOwnProperty(name);
			}

			return {
				invoke : invoke,
				instantiate : instantiate,
				get : getService,
				annotate : annotate,
				has : has,
				$cache : cache
			};
		}

	}

	///////////////////////////////////////////////////////////////////////////////////////////////////////////////
	function vxSetupServices() {
		var mod = vx.module('v');
		mod.provider({
			$animation : $AnimationProvider,
			$animator : $AnimatorProvider,
			$browser : $BrowserProvider,
			$cacheFactory : $CacheFactoryProvider,
			$compile : $CompileProvider,
			$controller : $ControllerProvider,
			$document : $DocumentProvider,
			//$exceptionHandler : $ExceptionHandlerProvider,
			$filter : $FilterProvider,
			$interpolate : $InterpolateProvider,
			$http : $HttpProvider,
			$httpBackend : $HttpBackendProvider,
			$log : $LogProvider,
			$parse : $ParseProvider,
			$rootScope : $RootScopeProvider,
			$q : $QProvider,
			$sniffer : $SnifferProvider,
			$templateCache : $TemplateCacheProvider,
			$window : $WindowProvider,
			$timeout : $TimeoutProvider,
			$targets : $TargetsProvider,
			$$remote : $$RemoteProvider,
			$validation : $ValidationProvider
		});
	}

	/**
	 * @vxdoc object
	 * @name vx.$animationProvider
	 * @description
	 *
	 * The $AnimationProvider provider allows developers to register and access custom JavaScript animations directly inside
	 * of a module.
	 *
	 */
	$AnimationProvider.$inject = ['$provide'];
	function $AnimationProvider($provide) {
		var suffix = 'Animation';

		/**
		 * @vxdoc function
		 * @name vx.$animation#register
		 * @methodOf vx.$animationProvider
		 *
		 * @description
		 * Registers a new injectable animation factory function. The factory function produces the animation object which
		 * has these two properties:
		 *
		 *   * `setup`: `function(Element):*` A function which receives the starting state of the element. The purpose
		 *   of this function is to get the element ready for animation. Optionally the function returns an memento which
		 *   is passed to the `start` function.
		 *   * `start`: `function(Element, doneFunction, *)` The element to animate, the `doneFunction` to be called on
		 *   element animation completion, and an optional memento from the `setup` function.
		 *
		 * @param {string} name The name of the animation.
		 * @param {function} factory The factory function that will be executed to return the animation object.
		 *
		 */
		this.register = function(name, factory) {
			$provide.factory(camelCase(name) + suffix, factory);
		};

		this.$get = ['$injector',
		function($injector) {
			/**
			 * @vxdoc function
			 * @name vx.$animation
			 * @function
			 *
			 * @description
			 * The $animation service is used to retrieve any defined animation functions. When executed, the $animation service
			 * will return a object that contains the setup and start functions that were defined for the animation.
			 *
			 * @param {String} name Name of the animation function to retrieve. Animation functions are registered and stored
			 *        inside of the VX DI so a call to $animate('custom') is the same as injecting `customAnimation`
			 *        via dependency injection.
			 * @return {Object} the animation object which contains the `setup` and `start` functions that perform the animation.
			 */
			return function $animation(name) {
				if (name) {
					var animationName = camelCase(name) + suffix;
					if ($injector.has(animationName)) {
						return $injector.get(animationName);
					}
				}
			};
		}];
	}

	// NOTE: this is a pseudo directive.

	/**
	 * @vxdoc directive
	 * @name vx.directive:vAnimate
	 *
	 * @description
	 * The `vAnimate` directive works as an attribute that is attached alongside pre-existing directives.
	 * It effects how the directive will perform DOM manipulation. This allows for complex animations to take place
	 * without burdening the directive which uses the animation with animation details. The built in directives
	 * `vRepeat`, `vInclude`, `vSwitch`, `vShow`, `vHide` and `vView` already accept `vAnimate` directive.
	 * Custom directives can take advantage of animation through {@link vx.$animator $animator service}.
	 *
	 * Below is a more detailed breakdown of the supported callback events provided by pre-exisitng vx directives:
	 *
	 * | Directive                                                 | Supported Animations                               |
	 * |========================================================== |====================================================|
	 * | {@link vx.directive:vRepeat#animations vRepeat}         | enter, leave and move                              |
	 * | {@link vx.directive:vView#animations vView}             | enter and leave                                    |
	 * | {@link vx.directive:vInclude#animations vInclude}       | enter and leave                                    |
	 * | {@link vx.directive:vSwitch#animations vSwitch}         | enter and leave                                    |
	 * | {@link vx.directive:vIf#animations vIf}                 | enter and leave                                    |
	 * | {@link vx.directive:vShow#animations vShow & vHide}    | show and hide
	 *
	 * You can find out more information about animations upon visiting each directive page.
	 *
	 * Below is an example of a directive that makes use of the vAnimate attribute:
	 *
	 * <pre>
	 * <!-- you can also use data-v-animate, v:animate or x-v-animate as well -->
	 * <ANY v-directive v-animate="{event1: 'animation-name', event2: 'animation-name-2'}"></ANY>
	 *
	 * <!-- you can also use a short hand -->
	 * <ANY v-directive v-animate=" 'animation' "></ANY>
	 * <!-- which expands to -->
	 * <ANY v-directive v-animate="{ enter: 'animation-enter', leave: 'animation-leave', ...}"></ANY>
	 *
	 * <!-- keep in mind that v-animate can take expressions -->
	 * <ANY v-directive v-animate=" computeCurrentAnimation() "></ANY>
	 * </pre>
	 *
	 * The `event1` and `event2` attributes refer to the animation events specific to the directive that has been assigned.
	 *
	 * Keep in mind that if an animation is running, no child element of such animation can also be animated.
	 *
	 * <h2>CSS-defined Animations</h2>
	 * By default, vAnimate attaches two CSS classes per animation event to the DOM element to achieve the animation.
	 * It is up to you, the developer, to ensure that the animations take place using cross-browser CSS3 transitions as
	 * well as CSS animations.
	 * The following code below demonstrates how to perform animations using **CSS transitions** with vAnimate:
	 *
	 * <pre>
	 * <style type="text/css">
	 * /&#42;
	 *  The animate-enter CSS class is the event name that you
	 *  have provided within the vAnimate attribute.
	 * &#42;/
	 * .animate-enter {
	 *  -webkit-transition: 1s linear all; /&#42; Safari/Chrome &#42;/
	 *  -moz-transition: 1s linear all; /&#42; Firefox &#42;/
	 *  -o-transition: 1s linear all; /&#42; Opera &#42;/
	 *  transition: 1s linear all; /&#42; IE10+ and Future Browsers &#42;/
	 *
	 *  /&#42; The animation preparation code &#42;/
	 *  opacity: 0;
	 * }
	 *
	 * /&#42;
	 *  Keep in mind that you want to combine both CSS
	 *  classes together to avoid any CSS-specificity
	 *  conflicts
	 * &#42;/
	 * .animate-enter.animate-enter-active {
	 *  /&#42; The animation code itself &#42;/
	 *  opacity: 1;
	 * }
	 * </style>
	 *
	 * <div v-directive v-animate="{enter: 'animate-enter'}"></div>
	 * </pre>
	 *
	 * The following code below demonstrates how to perform animations using **CSS animations** with vAnimate:
	 *
	 * <pre>
	 * <style type="text/css">
	 * .animate-enter {
	 *   -webkit-animation: enter_sequence 1s linear; /&#42; Safari/Chrome &#42;/
	 *   -moz-animation: enter_sequence 1s linear; /&#42; Firefox &#42;/
	 *   -o-animation: enter_sequence 1s linear; /&#42; Opera &#42;/
	 *   animation: enter_sequence 1s linear; /&#42; IE10+ and Future Browsers &#42;/
	 * }
	 * &#64-webkit-keyframes enter_sequence {
	 *   from { opacity:0; }
	 *   to { opacity:1; }
	 * }
	 * &#64-moz-keyframes enter_sequence {
	 *   from { opacity:0; }
	 *   to { opacity:1; }
	 * }
	 * &#64-o-keyframes enter_sequence {
	 *   from { opacity:0; }
	 *   to { opacity:1; }
	 * }
	 * &#64keyframes enter_sequence {
	 *   from { opacity:0; }
	 *   to { opacity:1; }
	 * }
	 * </style>
	 *
	 * <div v-directive v-animate="{enter: 'animate-enter'}"></div>
	 * </pre>
	 *
	 * vAnimate will first examine any CSS animation code and then fallback to using CSS transitions.
	 *
	 * Upon DOM mutation, the event class is added first, then the browser is allowed to reflow the content and then,
	 * the active class is added to trigger the animation. The vAnimate directive will automatically extract the duration
	 * of the animation to determine when the animation ends. Once the animation is over then both CSS classes will be
	 * removed from the DOM. If a browser does not support CSS transitions or CSS animations then the animation will start and end
	 * immediately resulting in a DOM element that is at it's final state. This final state is when the DOM element
	 * has no CSS transition/animation classes surrounding it.
	 *
	 * <h2>JavaScript-defined Animations</h2>
	 * In the event that you do not want to use CSS3 transitions or CSS3 animations or if you wish to offer animations to browsers that do not
	 * yet support them, then you can make use of JavaScript animations defined inside of your vx module.
	 *
	 * <pre>
	 * var vModule = vx.module('YourApp', []);
	 * vModule.animation('animate-enter', function() {
	 *   return {
	 *     setup : function(element) {
	 *       //prepare the element for animation
	 *       element.css({ 'opacity': 0 });
	 *       var memo = "..."; //this value is passed to the start function
	 *       return memo;
	 *     },
	 *     start : function(element, done, memo) {
	 *       //start the animation
	 *       element.animate({
	 *         'opacity' : 1
	 *       }, function() {
	 *         //call when the animation is complete
	 *         done()
	 *       });
	 *     }
	 *   }
	 * });
	 * </pre>
	 *
	 * As you can see, the JavaScript code follows a similar template to the CSS3 animations. Once defined, the animation
	 * can be used in the same way with the vAnimate attribute. Keep in mind that, when using JavaScript-enabled
	 * animations, vAnimate will also add in the same CSS classes that CSS-enabled animations do (even if you're not using
	 * CSS animations) to animated the element, but it will not attempt to find any CSS3 transition or animation duration/delay values.
	 * It will instead close off the animation once the provided done function is executed. So it's important that you
	 * make sure your animations remember to fire off the done function once the animations are complete.
	 *
	 * @param {expression} vAnimate Used to configure the DOM manipulation animations.
	 *
	 */

	var $AnimatorProvider = function() {
		var V_ANIMATE_CONTROLLER = '$vAnimateController';
		var rootAnimateController = {
			running : true
		};

		this.$get = ['$animation', '$window', '$sniffer', '$rootElement', '$rootScope',
		function($animation, $window, $sniffer, $rootElement, $rootScope) {
			$rootElement.data(V_ANIMATE_CONTROLLER, rootAnimateController);

			/**
			 * @vxdoc function
			 * @name vx.$animator
			 * @function
			 *
			 * @description
			 * The $animator service provides the DOM manipulation API which is decorated with animations.
			 *
			 * @param {Scope} scope the scope for the v-animate.
			 * @param {Attributes} attr the attributes object which contains the vAnimate key / value pair. (The attributes are
			 *        passed into the linking function of the directive using the `$animator`.)
			 * @return {object} the animator object which contains the enter, leave, move, show, hide and animate methods.
			 */
			var AnimatorService = function(scope, attrs) {
				var animator = {};

				/**
				 * @vxdoc function
				 * @name vx.animator#enter
				 * @methodOf vx.$animator
				 * @function
				 *
				 * @description
				 * Injects the element object into the DOM (inside of the parent element) and then runs the enter animation.
				 *
				 * @param {jQuery/jqLite element} element the element that will be the focus of the enter animation
				 * @param {jQuery/jqLite element} parent the parent element of the element that will be the focus of the enter animation
				 * @param {jQuery/jqLite element} after the sibling element (which is the previous element) of the element that will be the focus of the enter animation
				 */
				animator.enter = animateActionFactory('enter', insert, noop);

				/**
				 * @vxdoc function
				 * @name vx.animator#leave
				 * @methodOf vx.$animator
				 * @function
				 *
				 * @description
				 * Runs the leave animation operation and, upon completion, removes the element from the DOM.
				 *
				 * @param {jQuery/jqLite element} element the element that will be the focus of the leave animation
				 * @param {jQuery/jqLite element} parent the parent element of the element that will be the focus of the leave animation
				 */
				animator.leave = animateActionFactory('leave', noop, remove);

				/**
				 * @vxdoc function
				 * @name vx.animator#move
				 * @methodOf vx.$animator
				 * @function
				 *
				 * @description
				 * Fires the move DOM operation. Just before the animation starts, the animator will either append it into the parent container or
				 * add the element directly after the after element if present. Then the move animation will be run.
				 *
				 * @param {jQuery/jqLite element} element the element that will be the focus of the move animation
				 * @param {jQuery/jqLite element} parent the parent element of the element that will be the focus of the move animation
				 * @param {jQuery/jqLite element} after the sibling element (which is the previous element) of the element that will be the focus of the move animation
				 */
				animator.move = animateActionFactory('move', move, noop);

				/**
				 * @vxdoc function
				 * @name vx.animator#show
				 * @methodOf vx.$animator
				 * @function
				 *
				 * @description
				 * Reveals the element by setting the CSS property `display` to `block` and then starts the show animation directly after.
				 *
				 * @param {jQuery/jqLite element} element the element that will be rendered visible or hidden
				 */
				animator.show = animateActionFactory('show', show, noop);

				/**
				 * @vxdoc function
				 * @name vx.animator#hide
				 * @methodOf vx.$animator
				 *
				 * @description
				 * Starts the hide animation first and sets the CSS `display` property to `none` upon completion.
				 *
				 * @param {jQuery/jqLite element} element the element that will be rendered visible or hidden
				 */
				animator.hide = animateActionFactory('hide', noop, hide);

				/**
				 * @vxdoc function
				 * @name vx.animator#animate
				 * @methodOf vx.$animator
				 *
				 * @description
				 * Triggers a custom animation event to be executed on the given element
				 *
				 * @param {string} event the name of the custom event
				 * @param {jQuery/jqLite element} element the element that will be animated
				 */
				animator.animate = function(event, element) {
					animateActionFactory(event, noop, noop)(element);
				};
				return animator;

				function animateActionFactory(type, beforeFn, afterFn) {
					return function(element, parent, after, backward) {
						var vAnimateValue = scope.$eval(attrs.vAnimate);
						var className = vAnimateValue ? isObject(vAnimateValue) ? vAnimateValue[type] : vAnimateValue + '-' + type : '';

						var animationPolyfill = $animation(className);
						var polyfillSetup = animationPolyfill && animationPolyfill.setup;
						var polyfillStart = animationPolyfill && animationPolyfill.start;
						var polyfillCancel = animationPolyfill && animationPolyfill.cancel;

						if (!className) {
							beforeFn(element, parent, after, backward);
							afterFn(element, parent, after, backward);
						} else {
							var activeClassName = className + '-active';
							if (backward) {
								className += '-backward';
								activeClassName += '-backward';
							}
							if (!parent) {
								parent = after ? after.parent() : element.parent();
							}
							if ((!$sniffer.transitions && !polyfillSetup && !polyfillStart) || (parent.inheritedData(V_ANIMATE_CONTROLLER) || noop).running) {
								beforeFn(element, parent, after, backward);
								afterFn(element, parent, after, backward);
								return;
							}

							var animationData = element.data(V_ANIMATE_CONTROLLER) || {};
							if (animationData.running) {
								(polyfillCancel || noop)(element);
								animationData.done();
							}
							element.data(V_ANIMATE_CONTROLLER, {
								running : true,
								done : done
							});

							element.addClass(className);
							beforeFn(element, parent, after, backward);
							if (element.length === 0)
								return done();

							var memento = (polyfillSetup || noop)(element, backward);

							// $window.setTimeout(beginAnimation, 0); this was causing the element not to animate
							// keep at 1 for animation dom rerender
							$window.setTimeout(beginAnimation, 1);
						}

						function parseMaxTime(str) {
							var total = 0, values = isString(str) ? str.split(/\s*,\s*/) : [];
							forEach(values, function(value) {
								total = Math.max(parseFloat(value) || 0, total);
							});
							return total;
						}

						function beginAnimation() {
							element.addClass(activeClassName);
							if (polyfillStart) {
								polyfillStart(element, done, memento);
							} else if (isFunction($window.getComputedStyle)) {
								//one day all browsers will have these properties
								var w3cAnimationProp = 'animation';
								var w3cTransitionProp = 'transition';

								//but some still use vendor-prefixed styles
								var vendorAnimationProp = $sniffer.vendorPrefix + 'Animation';
								var vendorTransitionProp = $sniffer.vendorPrefix + 'Transition';

								var durationKey = 'Duration', delayKey = 'Delay', animationIterationCountKey = 'IterationCount', duration = 0;

								//we want all the styles defined before and after
								var ELEMENT_NODE = 1;
								forEach(element, function(element) {
									if (element.nodeType == ELEMENT_NODE) {
										var elementStyles = $window.getComputedStyle(element) || {};

										var transitionDelay = Math.max(parseMaxTime(elementStyles[w3cTransitionProp + delayKey]), parseMaxTime(elementStyles[vendorTransitionProp + delayKey]));

										var animationDelay = Math.max(parseMaxTime(elementStyles[w3cAnimationProp + delayKey]), parseMaxTime(elementStyles[vendorAnimationProp + delayKey]));

										var transitionDuration = Math.max(parseMaxTime(elementStyles[w3cTransitionProp + durationKey]), parseMaxTime(elementStyles[vendorTransitionProp + durationKey]));

										var animationDuration = Math.max(parseMaxTime(elementStyles[w3cAnimationProp + durationKey]), parseMaxTime(elementStyles[vendorAnimationProp + durationKey]));

										if (animationDuration > 0) {
											animationDuration *= Math.max(int(elementStyles[w3cAnimationProp + animationIterationCountKey]) || 0, int(elementStyles[vendorAnimationProp + animationIterationCountKey]) || 0, 1);
										}

										duration = Math.max(animationDelay + animationDuration, transitionDelay + transitionDuration, duration);
									}
								});
								$window.setTimeout(done, duration * 1000);
							} else {
								done();
							}
						}

						function done() {
							if (!done.run) {
								done.run = true;
								afterFn(element, parent, after, backward);
								element.removeClass(className);
								element.removeClass(activeClassName);
								element.removeData(V_ANIMATE_CONTROLLER);
							}
						}

					};
				}

				function show(element) {
					element.css('display', '');
				}

				function hide(element) {
					element.css('display', 'none');
				}

				function insert(element, parent, after) {
					var afterNode = after && after[after.length - 1];
					var parentNode = parent && parent[0] || afterNode && afterNode.parentNode;
					var afterNextSibling = afterNode && afterNode.nextSibling;
					forEach(element, function(node) {
						if (afterNextSibling) {
							parentNode.insertBefore(node, afterNextSibling);
						} else {
							parentNode.appendChild(node);
						}
					});
				}

				function remove(element) {
					element.remove();
				}

				function move(element, parent, after) {
					// Do not remove element before insert. Removing will cause data associated with the
					// element to be dropped. Insert will implicitly do the remove.
					insert(element, parent, after);
				}

			};
			/**
			 * @vxdoc function
			 * @name vx.animator#enabled
			 * @methodOf vx.$animator
			 * @function
			 *
			 * @param {Boolean=} If provided then set the animation on or off.
			 * @return {Boolean} Current animation state.
			 *
			 * @description
			 * Globally enables/disables animations.
			 *
			 */
			AnimatorService.enabled = function(value) {
				if (arguments.length) {
					rootAnimateController.running = !value;
				}
				return !rootAnimateController.running;
			};

			return AnimatorService;
		}];
	};

	////////////////////////////////
	// $WindowProvider
	///////////////////////////////

	/**
	 * @vxdoc object
	 * @name vx.$window
	 *
	 * @description
	 * A reference to the browser's `window` object. While `window`
	 * is globally available in JavaScript, it causes testability problems, because
	 * it is a global variable. In vx we always refer to it through the
	 * `$window` service, so it may be overridden, removed or mocked for testing.
	 *
	 * All expressions are evaluated with respect to current scope so they don't
	 * suffer from window globality.
	 *
	 * @example
	 <doc:example>
	 <doc:source>
	 <script>
	 function Ctrl($scope, $window) {
	 $scope.$window = $window;
	 $scope.greeting = 'Hello, World!';
	 }
	 </script>
	 <div v-controller="Ctrl">
	 <input type="text" v-model="greeting" />
	 <button v-click="$window.alert(greeting)">ALERT</button>
	 </div>
	 </doc:source>
	 <doc:scenario>
	 it('should display the greeting in the input box', function() {
	 input('greeting').enter('Hello, E2E Tests');
	 // If we click the button it will block the test runner
	 // element(':button').click();
	 });
	 </doc:scenario>
	 </doc:example>
	 */
	function $WindowProvider() {
		this.$get = valueFn(window);
	}

	////////////////////////////////
	// $DocumentProvider
	///////////////////////////////

	/**
	 * @vxdoc object
	 * @name vx.$document
	 * @requires $window
	 *
	 * @description
	 * A {@link vx.element jQuery (lite)}-wrapped reference to the browser's `window.document`
	 * element.
	 */
	function $DocumentProvider() {
		this.$get = ['$window',
		function(window) {
			return jqLite(window.document);
		}];

	}

	// used by $log
	function formatError(arg) {
		if ( arg instanceof Error) {
			if (arg.stack) {
				arg = (arg.message && arg.stack.indexOf(arg.message) === -1) ? 'Error: ' + arg.message + '\n' + arg.stack : arg.stack;
			} else if (arg.sourceURL) {
				arg = arg.message + '\n' + arg.sourceURL + ':' + arg.line;
			}
		}
		return arg;
	}

	function $LogProvider() {
		var fallback, console = window.console || (window.console = {}), logger = (function() {
			var originalFunctions = [], levels = ['debug', 'info', 'warn', 'error'];
			function init(minLevel) {
				minLevel = minLevel || 'info';
				var clear = false, unsupport = function() {
					if (fallback)
						_fastInvoke(fallback, logger, arguments);
				};
				console.log = console.log || unsupport;
				for (var i = 0; i < levels.length; i++) {
					var level = levels[i];
					originalFunctions[i] = originalFunctions[i] || console[level] || (level === 'debug' ? console.log : unsupport);
					if (level && (clear || level === minLevel)) {
						console[level] = originalFunctions[i];
						clear = true;
					} else {
						console[level] = suppressed(level);
					}
				}
			}

			function reset() {
				for (var i = originalFunctions.length; i >= 0; i--) {
					console[levels[i]] = originalFunctions[i];
				}
				originalFunctions = [];
			}

			init('debug');
			return {
				levels : levels,
				init : init,
				reset : reset
			};

			function suppressed(level) {
				return function() {
					return level + ' suppressed';
				};
			}

		})();

		this.setLevel = function(level) {
			logger.init(level);
		};

		this.setFallback = function(p) {
			fallback = p;
		};

		this.$get = valueFn(console);
	}

	////////////////////////////////
	// $ExceptionHandlerProvider
	///////////////////////////////

	/**
	 * @vxdoc function
	 * @name vx.$exceptionHandler
	 * @requires $log
	 *
	 * @description
	 * Any uncaught exception in vx expressions is delegated to this service.
	 * The default implementation simply delegates to `$log.error` which logs it into
	 * the browser console.
	 *
	 * In unit tests, if `vx-mocks.js` is loaded, this service is overridden by
	 * {@link vMock.$exceptionHandler mock $exceptionHandler} which aids in testing.
	 *
	 * @param {Error} exception Exception associated with the error.
	 * @param {string=} cause optional information about the context in which
	 *       the error was thrown.
	 */
	/*
	function $ExceptionHandlerProvider() {
	this.$get = ['$log',
	function($log) {
	return function(exception, cause) {
	// XXX call will lose line number
	//$log.error.apply($log, arguments);
	};
	}];

	}
	*/

	////////////////////////////////
	// $SnifferProvider
	///////////////////////////////

	/**
	 * !!! This is an undocumented "private" service !!!
	 *
	 * @name vx.$sniffer
	 * @requires $window
	 * @requires $document
	 *
	 * @property {boolean} history Does the browser support html5 history api ?
	 * @property {boolean} hashchange Does the browser support hashchange event ?
	 * @property {boolean} transitions Does the browser support CSS transition events ?
	 * @property {boolean} animations Does the browser support CSS animation events ?
	 *
	 * @description
	 * This is very simple implementation of testing browser's features.
	 */
	function $SnifferProvider() {
		this.$get = ['$window', '$document',
		function($window, $document) {
			var eventSupport = {}, //
			android = int((/android (\d+)/.exec(lowercase(($window.navigator || {}).userAgent)) || [])[1]), //
			document = $document[0] || {}, //
			vendorPrefix, //
			vendorRegex = /^(Moz|webkit|O|ms)(?=[A-Z])/, //
			bodyStyle = document.body && document.body.style, //
			transitions = false, //
			animations = false, //
			match;

			if (bodyStyle) {
				for (var prop in bodyStyle) {
					/*jshint boss:true */
					if ( match = vendorRegex.exec(prop)) {
						vendorPrefix = match[0];
						vendorPrefix = vendorPrefix.substr(0, 1).toUpperCase() + vendorPrefix.substr(1);
						break;
					}
				}
				transitions = !!(('transition' in bodyStyle) || (vendorPrefix + 'Transition' in bodyStyle));
				animations = !!(('animation' in bodyStyle) || (vendorPrefix + 'Animation' in bodyStyle));
			}
			return {
				// Android has history.pushState, but it does not update location correctly
				// so let's not use the history API at all.
				// http://code.google.com/p/android/issues/detail?id=17471
				// https://github.com/vx/vx.js/issues/904
				android : android,
				history : !!($window.history && $window.history.pushState && (!android || android >= 4)),
				hashchange : 'onhashchange' in $window &&
				// IE8 compatible mode lies
				(!document.documentMode || document.documentMode > 7),
				hasEvent : function(event) {
					// IE9 implements 'input' event it's so fubared that we rather pretend that it doesn't have
					// it. In particular the event is not fired when backspace or delete key are pressed or
					// when cut operation is performed.
					if (event == 'input' && msie == 9)
						return false;

					if (isUndefined(eventSupport[event])) {
						var divElm = document.createElement('div');
						eventSupport[event] = 'on' + event in divElm;
						if (msie)
							IE_GC(divElm);
					}
					return eventSupport[event];
				},
				csp : document.securityPolicy ? document.securityPolicy.isActive : false,
				vendorPrefix : vendorPrefix,
				transitions : transitions,
				animations : animations
			};
		}];

	}

	////////////////////////////////
	// $BrowserProvider
	///////////////////////////////

	function $BrowserProvider() {
		//XXX in e2etest, debounce must be disable, otherwise the state of form and inputs can not get immediately
		var e2eTest = false;
		this.setE2ETest = function(m) {
			e2eTest = !!m;
		};

		/**
		 * ! This is a private undocumented service !
		 *
		 * @name vx.$browser
		 * @requires $log
		 * @description
		 * This object has two goals:
		 *
		 * - hide all the global state in the browser caused by the window object
		 * - abstract away all the browser specific features and inconsistencies
		 *
		 * For tests we provide {@link vMock.$browser mock implementation} of the `$browser`
		 * service, which can be used for convenient testing of the application without the interaction with
		 * the real browser APIs.
		 */
		/**
		 * @param {object} window The global window object.
		 * @param {object} document jQuery wrapped document.
		 * @param {function()} XHR XMLHttpRequest constructor.
		 * @param {object} $log console.log or an object with the same interface.
		 * @param {object} $sniffer $sniffer service
		 */
		function Browser(window, document, $log, $sniffer) {
			var self = this, rawDocument = document[0], location = window.location, history = window.history, //
			setTimeout = window.setTimeout, clearTimeout = window.clearTimeout, pendingDeferIds = {};
			self.isMock = false;

			var outstandingRequestCount = 0;
			var outstandingRequestCallbacks = [];

			// TODO(vojta): remove this temporary api
			self.$$completeOutstandingRequest = completeOutstandingRequest;
			self.$$incOutstandingRequestCount = function() {
				outstandingRequestCount++;
			};
			/**
			 * Executes the `fn` function(supports currying) and decrements the `outstandingRequestCallbacks`
			 * counter. If the counter reaches 0, all the `outstandingRequestCallbacks` are executed.
			 */
			function completeOutstandingRequest(fn) {
				try {
					_fastInvoke(fn, null, sliceArgs(arguments, 1));
				} finally {
					outstandingRequestCount--;
					if (outstandingRequestCount === 0) {
						while (outstandingRequestCallbacks.length) {
							try {
								outstandingRequestCallbacks.pop()();
							} catch (e) {
								$log.error(formatError(e));
							}
						}
					}
				}
			}

			/**
			 * @private
			 * Note: this method is used only by scenario runner
			 * @param {function()} callback Function that will be called when no outstanding request
			 */
			self.$$notifyWhenNoOutstandingRequests = function(callback) {
				// force browser to execute all pollFns - this is needed so that cookies and other pollers fire
				// at some deterministic time in respect to the test runner's actions. Leaving things up to the
				// regular poller would result in flaky tests.
				forEach(pollFns, function(pollFn) {
					pollFn();
				});
				if (outstandingRequestCount === 0) {
					callback();
				} else {
					outstandingRequestCallbacks.push(callback);
				}
			};
			//***************************
			// Poll Watcher API
			//***************************
			var pollFns = [], pollTimeout;

			/**
			 * @name vx.$browser#addPollFn
			 * @methodOf vx.$browser
			 *
			 * @param {function()} fn Poll function to add
			 *
			 * @description
			 * Adds a function to the list of functions that poller periodically executes,
			 * and starts polling if not started yet.
			 *
			 * @returns {function()} the added function
			 */
			self.addPollFn = function(fn) {
				if (isUndefined(pollTimeout))
					startPoller(100, setTimeout);
				pollFns.push(fn);
				return fn;
			};
			/**
			 * @param {number} interval How often should browser call poll functions (ms)
			 * @param {function()} setTimeout Reference to a real or fake `setTimeout` function.
			 *
			 * @description
			 * Configures the poller to run in the specified intervals, using the specified
			 * setTimeout fn and kicks it off.
			 */
			function startPoller(interval, setTimeout) {
				(function check() {
					forEach(pollFns, function(pollFn) {
						pollFn();
					});
					pollTimeout = setTimeout(check, interval);
				})();
			}

			//**********************
			// URL API
			//**********************
			var lastBrowserUrl = location.href, baseElement = document.find('base');

			/**
			 * @name vx.$browser#url
			 * @methodOf vx.$browser
			 *
			 * @description
			 * GETTER:
			 * Without any argument, this method just returns current value of location.href.
			 *
			 * SETTER:
			 * With at least one argument, this method sets url to new value.
			 * If html5 history api supported, pushState/replaceState is used, otherwise
			 * location.href/location.replace is used.
			 * Returns its own instance to allow chaining
			 *
			 * NOTE: this api is intended for use only by the $location service. Please use the
			 * {@link vx.$location $location service} to change url.
			 *
			 * @param {string} url New url (when used as setter)
			 * @param {boolean=} replace Should new url replace current history record ?
			 */
			self.url = function(url, replace) {
				if (url) {// setter
					if (lastBrowserUrl == url)
						return;
					lastBrowserUrl = url;
					if ($sniffer.history) {
						if (replace)
							history.replaceState(null, '', url);
						else {
							history.pushState(null, '', url);
							// Crazy Opera Bug: http://my.opera.com/community/forums/topic.dml?id=1185462
							baseElement.attr('href', baseElement.attr('href'));
						}
					} else {
						$$url(url, replace);
					}
					return self;
				} else {// getter
					return $$url();
				}
			};

			var $$url = function urlGetterSetter(url, replace) {
				if (url) {
					if (replace)
						location.replace(url);
					else
						location.href = url;
				} else {
					// the replacement is a workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=407172
					return location.href.replace(/%27/g, "'");
				}
			};

			self.hash = function(hash) {
				if (hash) {
					location.hash = hash;
					return self;
				} else {
					return location.hash;
				}
			};

			self.useHistory = function() {
				if (msie < 8) {
					var ieHandler = {
						iframe : jqLite('<iframe id="vx_IE_sudo_history_Frame" style="display:none" src="javascript:false;"></iframe>').prependTo('body')[0],
						getLoc : function(update) {
							var doc = this.iframe.contentWindow.document;
							if (update) {
								doc.open();
								doc.close();
							}
							return doc.location;
						},
						url : function(url, replace) {
							if (!url)
								return this.getLoc().href;
							if (replace)
								this.getLoc(true).replace(url);
							else
								this.getLoc(true).href = url;
						},
						hash : function(hash) {
							if (!hash)
								return this.getLoc().hash;
							this.getLoc(true).hash = hash;
						}
					};
					ieHandler.url(location.href);
					$$url = function urlGetterSetter(url, replace) {
						if (url) {
							ieHandler.url(url, replace);
						} else {
							return ieHandler.url();
						}
					};
					self.hash = function(hash) {
						if (hash) {
							ieHandler.hash(hash);
							return self;
						} else {
							return ieHandler.hash();
						}
					};
				}

				if (!$sniffer.history && $sniffer.android) {
					var sudoLink = jqLite('<a href="#" id="vx_android_sudo_history" style="display:none">Hash_Forward</a>').prependTo('body');
				}

				self.History = {
					add : function(state, url) {
						if ($sniffer.history) {
							history.pushState(state, null, url);
							fireUrlChange();
						} else {
							//XXX android native browser 2.3-4.1 has no history.pushState,
							//       and cannot refresh address bar synchronized
							//       so emulate 'click' trigger history tracking
							if (sudoLink) {
								sudoLink.attr('href', url);
								//XXX webkit cannot click() except input and button, so use dispatch
								try {
									var event = document.createEvent("Event");
									event.initEvent('click', true, true);
									sudoLink[0].dispatchEvent(event);
								} catch (d) {
									$log.error('cannot dispatch "click" on sudoLink');
								}
							} else {
								self.hash(url);
							}
						}
					},
					go : function(steps) {
						history.go(steps);
					},
					reload : function(steps) {
						$log.debug('reload base url "' + self.baseUrl + '"');
						if (steps) {
							//XXX use location.replace(...) keep browser history tracking
							if (!$sniffer.history && !$sniffer.android/*webkit*/) {
								// in ie/firefox, will clear history directly, but webkit is so different
								history.go(steps);
								update();
							} else {
								// webkit, history.go is async, so defer location.replace(...)
								history.go(steps);
								self.defer(function() {
									update();
								}, 0);
							}
						} else {
							update();
						}

						function update() {
							location.replace(self.baseUrl);
						}

					}
				};
			};

			var urlChangeListeners = [], urlChangeInit = false;
			function fireUrlChange() {
				if (lastBrowserUrl == self.url())
					return;
				lastBrowserUrl = self.url();
				forEach(urlChangeListeners, function(listener) {
					listener(self.url());
				});
			}

			/**
			 * @name vx.$browser#onUrlChange
			 * @methodOf vx.$browser
			 * @TODO(vojta): refactor to use node's syntax for events
			 *
			 * @description
			 * Register callback function that will be called, when url changes.
			 *
			 * It's only called when the url is changed by outside of vx:
			 * - user types different url into address bar
			 * - user clicks on history (forward/back) button
			 * - user clicks on a link
			 *
			 * It's not called when url is changed by $browser.url() method
			 *
			 * The listener gets called with new url as parameter.
			 *
			 * NOTE: this api is intended for use only by the $location service. Please use the
			 * {@link vx.$location $location service} to monitor url changes in vx apps.
			 *
			 * @param {function(string)} listener Listener function to be called when url changes.
			 * @return {function(string)} Returns the registered listener fn - handy if the fn is anonymous.
			 */
			self.onUrlChange = function(callback) {
				if (!urlChangeInit) {
					// We listen on both (hashchange/popstate) when available, as some browsers (e.g. Opera)
					// don't fire popstate when user change the address bar and don't fire hashchange when url
					// changed by push/replaceState

					// html5 history api - popstate event
					if ($sniffer.history)
						jqLite(window).bind('popstate', fireUrlChange);
					// hashchange event
					if ($sniffer.hashchange)
						jqLite(window).bind('hashchange', fireUrlChange);

					if (!$sniffer.history && !$sniffer.hashchange)
						self.addPollFn(fireUrlChange);
					urlChangeInit = true;
				}

				urlChangeListeners.push(callback);
				return callback;
			};

			//////////////////////////////////////////////////////////////
			// Misc API
			//////////////////////////////////////////////////////////////
			self.baseUrl = (function baseUrl() {
				var href = baseElement.attr('href') || self.url();
				if (href.indexOf('#') !== -1)
					href = href.substring(0, href.indexOf('#'));
				return href;
			})();

			/**
			 * Returns current <base href>
			 * (always relative - without domain)
			 *
			 * @returns {string=}
			 */
			self.baseHref = function() {
				return self.baseUrl.replace(/^https?\:\/\/[^\/]*/, '');
				//var href = baseElement.attr('href');
				//return href ? href.replace(/^https?\:\/\/[^\/]*/, '') : href;
			};
			//****************************
			// Cookies API
			//****************************
			var lastCookies = {};
			var lastCookieString = '';
			var cookiePath = self.baseHref();

			/**
			 * @name vx.$browser#cookies
			 * @methodOf vx.$browser
			 *
			 * @param {string=} name Cookie name
			 * @param {string=} value Cookie value
			 *
			 * @description
			 * The cookies method provides a 'private' low level access to browser cookies.
			 * It is not meant to be used directly, use the $cookie service instead.
			 *
			 * The return values vary depending on the arguments that the method was called with as follows:
			 * <ul>
			 *   <li>cookies() -> hash of all cookies, this is NOT a copy of the internal state, so do not modify it</li>
			 *   <li>cookies(name, value) -> set name to value, if value is undefined delete the cookie</li>
			 *   <li>cookies(name) -> the same as (name, undefined) == DELETES (no one calls it right now that way)</li>
			 * </ul>
			 *
			 * @returns {Object} Hash of all cookies (if called without any parameter)
			 */
			self.cookies = function(name, value) {
				var cookieLength, cookieArray, cookie, i, index;

				if (name) {
					if (value === undefined) {
						rawDocument.cookie = escape(name) + "=;path=" + cookiePath + ";expires=Thu, 01 Jan 1970 00:00:00 GMT";
					} else {
						if (isString(value)) {
							cookieLength = (rawDocument.cookie = escape(name) + '=' + escape(value) + ';path=' + cookiePath).length + 1;

							// per http://www.ietf.org/rfc/rfc2109.txt browser must allow at minimum:
							// - 300 cookies
							// - 20 cookies per unique domain
							// - 4096 bytes per cookie
							if (cookieLength > 4096) {
								$log.warn("Cookie '" + name + "' possibly not set or overflowed because it was too large (" + cookieLength + " > 4096 bytes)!");
							}
						}
					}
				} else {
					if (rawDocument.cookie !== lastCookieString) {
						lastCookieString = rawDocument.cookie;
						cookieArray = lastCookieString.split("; ");
						lastCookies = {};
						for ( i = 0; i < cookieArray.length; i++) {
							cookie = cookieArray[i];
							index = cookie.indexOf('=');
							if (index > 0) {//ignore nameless cookies
								var n = unescape(cookie.substring(0, index));
								// the first value that is seen for a cookie is the most
								// specific one.  values for the same cookie name that
								// follow are for less specific paths.
								if (lastCookies[n] === undefined) {
									lastCookies[n] = unescape(cookie.substring(index + 1));
								}
							}
						}
					}
					return lastCookies;
				}
			};
			/**
			 * @name vx.$browser#defer
			 * @methodOf vx.$browser
			 * @param {function()} fn A function, who's execution should be defered.
			 * @param {number=} [delay=0] of milliseconds to defer the function execution.
			 * @returns {*} DeferId that can be used to cancel the task via `$browser.defer.cancel()`.
			 *
			 * @description
			 * Executes a fn asynchronously via `setTimeout(fn, delay)`.
			 *
			 * Unlike when calling `setTimeout` directly, in test this function is mocked and instead of using
			 * `setTimeout` in tests, the fns are queued in an array, which can be programmatically flushed
			 * via `$browser.defer.flush()`.
			 *
			 */
			self.defer = function(fn, delay) {
				var timeoutId;
				outstandingRequestCount++;
				timeoutId = setTimeout(function() {
					delete pendingDeferIds[timeoutId];
					completeOutstandingRequest(fn);
				}, delay || 0);
				pendingDeferIds[timeoutId] = true;
				return timeoutId;
			};
			/**
			 * @name vx.$browser#defer.cancel
			 * @methodOf vx.$browser.defer
			 *
			 * @description
			 * Cancels a defered task identified with `deferId`.
			 *
			 * @param {*} deferId Token returned by the `$browser.defer` function.
			 * @returns {boolean} Returns `true` if the task hasn't executed yet and was successfully canceled.
			 */
			self.defer.cancel = function(deferId) {
				if (pendingDeferIds[deferId]) {
					delete pendingDeferIds[deferId];
					clearTimeout(deferId);
					completeOutstandingRequest(noop);
					return true;
				}
				return false;
			};

			/**
			 * Creates a function that will delay the execution of `func` until after
			 * `wait` milliseconds have elapsed since the last time it was invoked. Pass
			 * `true` for `immediate` to cause debounce to invoke `func` on the leading,
			 * instead of the trailing, edge of the `wait` timeout. Subsequent calls to
			 * the debounced function will return the result of the last `func` call.
			 *
			 * @static
			 * @memberOf _
			 * @category Functions
			 * @param {Function} func The function to debounce.
			 * @param {Number} wait The number of milliseconds to delay.
			 * @param {Boolean} immediate A flag to indicate execution is on the leading
			 *  edge of the timeout.
			 * @returns {Function} Returns the new debounced function.
			 * @example
			 *
			 * var lazyLayout = _.debounce(calculateLayout, 300);
			 * jQuery(window).on('resize', lazyLayout);
			 */
			// this special version of debounce support immediate action deferred by delay action
			//****** for input/event and submit, submit must defer ensure input model correct
			var delayFns = [], deferFns = [];
			self.debounce = function(func, wait, immediate, defer) {
				if (e2eTest)
					return func;

				var timeoutId, result;

				function exec(thisArg, args) {
					var isImmediate = immediate && (defer || !timeoutId);
					clearTimeout(timeoutId);
					timeoutId = setTimeout(delayed, wait);
					if (isImmediate) {
						result = func.apply(thisArg, args);
					}
					return result;
					function delayed() {
						timeoutId = null;
						if (!immediate) {
							result = func.apply(thisArg, args);
						} else if ( typeof immediate == 'function') {
							immediate();
						}
						if (!defer) {
							arrayRemove(delayFns, exec);
							if (delayFns.length === 0) {
								for (var i = 0; i < deferFns.length; i++)
									deferFns[i]();
								deferFns = [];
							}
						}
					}

				}

				return function() {
					var thisArg = this, args = arguments;
					if (!defer) {
						if (indexOf(delayFns, exec) === -1)
							delayFns.push(exec);
					} else if (delayFns.length > 0) {
						deferFns.push(function() {
							return exec(thisArg, args);
						});
						return;
					}
					return exec(thisArg, args);
				};
			};
		}

		// original version debounce
		/*
		 self.debounce = function(func, wait, immediate) {
		 if (e2eTest)
		 return func;

		 var args, result, thisArg, timeoutId;

		 function delayed() {
		 timeoutId = null;
		 if (!immediate) {
		 result = func.apply(thisArg, args);
		 } else if ( typeof immediate == 'function') {
		 immediate();
		 }
		 }

		 return function() {
		 var isImmediate = immediate && !timeoutId;
		 args = arguments;
		 thisArg = this;

		 clearTimeout(timeoutId);
		 timeoutId = setTimeout(delayed, wait);

		 if (isImmediate) {
		 result = func.apply(thisArg, args);
		 }
		 return result;
		 };
		 };
		 }
		 */

		this.$get = ['$window', '$log', '$sniffer', '$document',
		function($window, $log, $sniffer, $document) {
			return new Browser($window, $document, $log, $sniffer);
		}];

	}

	////////////////////////////////
	// $CacheFactoryProvider
	///////////////////////////////

	/**
	 * @vxdoc object
	 * @name vx.$cacheFactory
	 *
	 * @description
	 * Factory that constructs cache objects.
	 *
	 *
	 * @param {string} cacheId Name or id of the newly created cache.
	 * @param {object=} options Options object that specifies the cache behavior. Properties:
	 *
	 *   - `{number=}` `capacity` — turns the cache into LRU cache.
	 *
	 * @returns {object} Newly created cache object with the following set of methods:
	 *
	 * - `{object}` `info()` — Returns id, size, and options of cache.
	 * - `{{*}}` `put({string} key, {*} value)` — Puts a new key-value pair into the cache and return it.
	 * - `{{*}}' `get({string} key) — Returns cached value for `key` or undefined for cache miss.
	 * - `{void}` `remove({string} key)' — Removes a key-value pair from the cache.
	 * - `{void}` `removeAll()' — Removes all cached values.
	 * - `{void}` `destroy()' — Removes references to this cache from $cacheFactory.
	 *
	 */
	function $CacheFactoryProvider() {
		this.$get = function() {
			var caches = {};
			function cacheFactory(cacheId, options) {
				if ( cacheId in caches) {
					throw vError(30, "CacheId '{0}' is already taken!", cacheId);
				}
				var size = 0, stats = extend({}, options, {
					id : cacheId
				}), data = {}, capacity = (options && options.capacity) || Number.MAX_VALUE, lruHash = {}, freshEnd = null, staleEnd = null;
				return caches[cacheId] = {
					key : function(key) {
						return key;
					},
					put : function(key, value) {
						key = this.key(key);
						var lruEntry = lruHash[key] || (lruHash[key] = {
							key : key
						});
						refresh(lruEntry);
						if (isUndefined(value))
							return;
						if (!( key in data))
							size++;
						data[key] = value;
						if (size > capacity) {
							this.remove(staleEnd.key);
						}
						return value;
					},
					get : function(key) {
						key = this.key(key);
						var lruEntry = lruHash[key];
						if (!lruEntry)
							return;
						refresh(lruEntry);
						return data[key];
					},
					remove : function(key) {
						key = this.key(key);
						var lruEntry = lruHash[key];
						if (!lruEntry)
							return;
						if (lruEntry == freshEnd)
							freshEnd = lruEntry.p;
						if (lruEntry == staleEnd)
							staleEnd = lruEntry.n;
						link(lruEntry.n, lruEntry.p);
						delete lruHash[key];
						delete data[key];
						size--;
					},
					removeAll : function() {
						data = {};
						size = 0;
						lruHash = {};
						freshEnd = staleEnd = null;
					},
					destroy : function() {
						data = null;
						stats = null;
						lruHash = null;
						delete caches[cacheId];
					},
					info : function() {
						return extend({}, stats, {
							size : size
						});
					}
				};

				/**
				 * makes the 'entry' the freshEnd of the LRU linked list
				 */
				function refresh(entry) {
					if (entry != freshEnd) {
						if (!staleEnd) {
							staleEnd = entry;
						} else if (staleEnd == entry) {
							staleEnd = entry.n;
						}
						link(entry.n, entry.p);
						link(entry, freshEnd);
						freshEnd = entry;
						freshEnd.n = null;
					}
				}

				/**
				 * bidirectionally links two entries of the LRU linked list
				 */
				function link(nextEntry, prevEntry) {
					if (nextEntry != prevEntry) {
						if (nextEntry)
							nextEntry.p = prevEntry;
						//p stands for previous, 'prev' didn't minify
						if (prevEntry)
							prevEntry.n = nextEntry;
						//n stands for next, 'next' didn't minify
					}
				}

			}


			cacheFactory.info = function() {
				var info = {};
				forEach(caches, function(cache, cacheId) {
					info[cacheId] = cache.info();
				});
				return info;
			};

			cacheFactory.get = function(cacheId) {
				return caches[cacheId];
			};
			return cacheFactory;
		};
	}

	////////////////////////////////
	// $TemplateCacheProvider
	///////////////////////////////
	/**
	 * @vxdoc object
	 * @name vx.$templateCache
	 *
	 * @description
	 * Cache used for storing html templates.
	 *
	 * See {@link vx.$cacheFactory $cacheFactory}.
	 *
	 */
	function $TemplateCacheProvider() {
		this.$get = ['$cacheFactory',
		function($cacheFactory) {
			var c = $cacheFactory('templates');
			var rts = /([?&])[_v]=[^&]*(&)?/;
			c.key = function(key) {
				if (isString(key)) {
					key = key.replace(rts, "$1");
				}
				return key;
			};
			return c;
		}];

	}

	////////////////////////////////
	// $TargetsProvider
	///////////////////////////////
	function $TargetsProvider() {
		var targets = {}, transitions = {}, trackLine = {
			count : 0,
			history : -1,
			index : 0,
			tracks : []
		}, useLocation = false;

		var DEFAULT_TRANSITION = function(oldEl, newEl, remove, back) {
			if (newEl && newEl.length) {
				if (oldEl && oldEl.length) {
					oldEl.css('display', 'none');
					if (remove)
						oldEl.remove();
				}
				newEl.css('display', '');
			}
		};

		this.useLocation = function(yes) {
			useLocation = !!yes;
		};

		function transition(name, fn) {
			var old = transitions[name];
			if (!fn)
				return old || DEFAULT_TRANSITION;
			transitions[name] = fn;
			return old;
		}


		this.transition = transition;

		Factory.$inject = ['$window', '$browser', '$log', '$rootScope'];
		function Factory(window, $browser, $log, $rootScope) {
			var viewports = {};

			if (useLocation)
				$browser.useHistory();

			forward.clearTarget = function(target) {
				viewports[target] = undefined;
				targets[target] = undefined;
			};

			/*
			 *  targets service, could be:
			 *  1. page fn(target, pageUrl[, active])
			 *  2. viewport
			 *     fn(target, url[, noHistory])
			 */
			function forward(target, urlExp, noHistory) {
				var view;
				if (isObject(target) && target.$trackPage) {// is ViewportController
					view = target;
				} else if (isString(target)) {
					view = viewports[target];
					if (!view)
						throw vError(31, 'no viewport found: {0}', target);
				} else {
					throw vError(32, 'target must be viewportController or its id');
				}
				target = view.$id;
				var old = targets[target], url = urlExp;
				if (!url)
					return old;

				if (url.indexOf('#') === 0) {
					var page = url.substring(1);
					view.$trackPage(page, true);
					return;
				}

				if (old && url === old.url)
					return;

				if (noHistory === undefined)
					noHistory = view.$noHistory;

				var current = {
					target : target,
					url : url
				};

				trackLine.count++;

				$log.debug('targets forward to "' + url + '" in "' + target + '" ' + (!noHistory ? '[with track]' : '[without track]'));

				if (!noHistory) {
					addHistory(current);
				}

				toViewport(target, current);
			}

			function addHistory(current) {
				if (trackLine.index >= 0 && trackLine.index <= trackLine.tracks.length) {
					trackLine.tracks.splice(trackLine.index, trackLine.tracks.length - trackLine.index, current);
				} else {
					throw vError(33, 'invalid history index: {0}', trackLine.index);
				}
				trackLine.index++;
				if (useLocation) {
					var loc = "#/$" + trackLine.index;
					$browser.History.add({
						index : trackLine.index
					}, loc);
					trackLine.history = window.history.length;
				}
			}

			function toViewport(target, track, back) {
				targets[target] = track;
				viewports[target].$load(track, back);
			}

			function trackHistory(index) {
				var back = index < trackLine.index;
				trackLine.index = index;
				var cur = trackLine.tracks[index - 1];
				$log.debug('targets track to "' + cur.url + '" in "' + cur.target + '"');
				toViewport(cur.target, cur, back);
			}

			if (useLocation) {
				$browser.onUrlChange(function(url) {
					var hash = $browser.hash();
					if (!hash || hash.indexOf('#/$') !== 0)
						return;
					var index = int(hash.substring(3));
					if (!isNumber(index) || index < 1)
						throw vError(34, 'invalid history index: {0}', index);
					if (index > trackLine.tracks.length)
						return;
					if (trackLine.index !== index) {
						trackHistory(index);
					}
				});
			}

			forward.track = function(steps) {
				var flag = steps.match(/^([\+\-]?)(\d+)$/);
				if (!flag)
					return;
				var n = int(steps);
				if (flag[1]) {// relative
					if (trackLine.tracks.length < 2)
						return;
					if (n <= -trackLine.index)
						n = -trackLine.index + 1;
					if (n > trackLine.tracks.length - trackLine.index)
						n = trackLine.tracks.length - trackLine.index;
					if (n === 0)
						return;
					if (useLocation) {
						$browser.History.go(n);
					} else {
						trackHistory(trackLine.index + n);
					}
				} else {
					if (n === 0) {
						//XXX n === 0 is special, it means reset history
						// history.count prevent reload dead loop
						if (trackLine.count > 1)
							return $browser.History.reload(-trackLine.index);
						return;
					}

					if (n > trackLine.tracks.length)
						throw vError(35, 'history over max index: {0}', trackLine.tracks.length);
					if (n === trackLine.index)
						return;
					if (useLocation) {
						$browser.History.go(n - trackLine.index);
					} else {
						trackHistory(n);
					}
				}
			};
			forward.track.info = trackLine;
			forward.transition = transition;

			forward.$viewports = viewports;

			return forward;
		}

		// return forward Factory
		this.$get = Factory;
	}

	//*****************************
	// $FilterProvider
	//*****************************

	/**
	 * @vxdoc object
	 * @name vx.$filterProvider
	 * @description
	 *
	 * Filters are just functions which transform input to an output. However filters need to be Dependency Injected. To
	 * achieve this a filter definition consists of a factory function which is annotated with dependencies and is
	 * responsible for creating a filter function.
	 *
	 * <pre>
	 *   // Filter registration
	 *   function MyModule($provide, $filterProvider) {
	 *     // create a service to demonstrate injection (not always needed)
	 *     $provide.value('greet', function(name){
	 *       return 'Hello ' + name + '!';
	 *     });
	 *
	 *     // register a filter factory which uses the
	 *     // greet service to demonstrate DI.
	 *     $filterProvider.register('greet', function(greet){
	 *       // return the filter function which uses the greet service
	 *       // to generate salutation
	 *       return function(text) {
	 *         // filters need to be forgiving so check input validity
	 *         return text && greet(text) || text;
	 *       };
	 *     });
	 *   }
	 * </pre>
	 *
	 * The filter function is registered with the `$injector` under the filter name suffixe with `Filter`.
	 * <pre>
	 *   it('should be the same instance', inject(
	 *     function($filterProvider) {
	 *       $filterProvider.register('reverse', function(){
	 *         return ...;
	 *       });
	 *     },
	 *     function($filter, reverseFilter) {
	 *       expect($filter('reverse')).toBe(reverseFilter);
	 *     });
	 * </pre>
	 *
	 *
	 * For more information about how vx filters work, and how to create your own filters, see
	 * {@link guide/dev_guide.templates.filters Understanding VX Filters} in the vx Developer
	 * Guide.
	 */
	/**
	 * @vxdoc method
	 * @name vx.$filterProvider#register
	 * @methodOf vx.$filterProvider
	 * @description
	 * Register filter factory function.
	 *
	 * @param {String} name Name of the filter.
	 * @param {function} fn The filter factory function which is injectable.
	 */

	/**
	 * @vxdoc function
	 * @name vx.$filter
	 * @function
	 * @description
	 * Filters are used for formatting data displayed to the user.
	 *
	 * The general syntax in templates is as follows:
	 *
	 *         {{ expression [| filter_name[:parameter_value] ... ] }}
	 *
	 * @param {String} name Name of the filter function to retrieve
	 * @return {Function} the filter function
	 */
	$FilterProvider.$inject = ['$provide'];
	function $FilterProvider($provide) {
		var suffix = 'Filter', register = this.register = function(name, factory) {
			return $provide.factory(name + suffix, factory);
		};

		this.$get = ['$injector',
		function($injector) {
			return function(name) {
				return $injector.get(name + suffix);
			};
		}];

	}

	////////////////////////////////
	// $ParseProvider
	///////////////////////////////
	/**
	 * @vxdoc function
	 * @name vx.$parse
	 * @function
	 *
	 * @description
	 *
	 * Converts VX {@link guide/expression expression} into a function.
	 *
	 * <pre>
	 *   var getter = $parse('user.name');
	 *   var setter = getter.assign;
	 *   var context = {user:{name:'vx'}};
	 *   var locals = {user:{name:'local'}};
	 *
	 *   expect(getter(context)).toEqual('vx');
	 *   setter(context, 'newValue');
	 *   expect(context.user.name).toEqual('newValue');
	 *   expect(getter(context, locals)).toEqual('local');
	 * </pre>
	 *
	 *
	 * @param {string} expression String expression to compile.
	 * @returns {function(context, locals)} a function which represents the compiled expression:
	 *
	 *    * `context` – `{object}` – an object against which any expressions embedded in the strings
	 *      are evaluated against (typically a scope object).
	 *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
	 *      `context`.
	 *
	 *    The returned function also has the following properties:
	 *      * `literal` – `{boolean}` – whether the expression's top-level node is a JavaScript
	 *        literal.
	 *      * `constant` – `{boolean}` – whether the expression is made entirely of JavaScript
	 *        constant literals.
	 *      * `assign` – `{?function(context, value)}` – if the expression is assignable, this will be
	 *        set to a function to change its value on the given context.
	 *
	 */
	function $ParseProvider() {
		var cache = {};
		this.$get = ['$filter', '$sniffer',
		function($filter, $sniffer) {
			return function(exp) {
				switch(typeof exp) {
					case 'string':
						return cache.hasOwnProperty(exp) ? cache[exp] : cache[exp] = EXPR.parser(exp, false, $filter, $sniffer.csp);
					case 'function':
						return exp;
					default:
						return noop;
				}
			};
		}];

	}

	////////////////////////////////
	// $InterpolateProvider
	///////////////////////////////

	/**
	 * @vxdoc object
	 * @name vx.$interpolateProvider
	 * @function
	 *
	 * @description
	 *
	 * Used for configuring the interpolation markup. Defaults to `{{` and `}}`.
	 */
	function $InterpolateProvider() {
		var startSymbol = '{{';
		var endSymbol = '}}';

		/**
		 * @vxdoc method
		 * @name vx.$interpolateProvider#startSymbol
		 * @methodOf vx.$interpolateProvider
		 * @description
		 * Symbol to denote start of expression in the interpolated string. Defaults to `{{`.
		 *
		 * @param {string=} value new value to set the starting symbol to.
		 * @returns {string|self} Returns the symbol when used as getter and self if used as setter.
		 */
		this.startSymbol = function(value) {
			if (value) {
				startSymbol = value;
				return this;
			} else {
				return startSymbol;
			}
		};
		/**
		 * @vxdoc method
		 * @name vx.$interpolateProvider#endSymbol
		 * @methodOf vx.$interpolateProvider
		 * @description
		 * Symbol to denote the end of expression in the interpolated string. Defaults to `}}`.
		 *
		 * @param {string=} value new value to set the ending symbol to.
		 * @returns {string|self} Returns the symbol when used as getter and self if used as setter.
		 */
		this.endSymbol = function(value) {
			if (value) {
				endSymbol = value;
				return this;
			} else {
				return endSymbol;
			}
		};

		this.$get = ['$parse', /*'$exceptionHandler',*/'$log',
		function($parse, /*$exceptionHandler,*/$log) {
			var startSymbolLength = startSymbol.length, endSymbolLength = endSymbol.length;

			/**
			 * @vxdoc function
			 * @name vx.$interpolate
			 * @function
			 *
			 * @requires $parse
			 *
			 * @description
			 *
			 * Compiles a string with markup into an interpolation function. This service is used by the
			 * HTML {@link vx.$compile $compile} service for data binding. See
			 * {@link vx.$interpolateProvider $interpolateProvider} for configuring the
			 * interpolation markup.
			 *
			 *
			 <pre>
			 var $interpolate = ...; // injected
			 var exp = $interpolate('Hello {{name}}!');
			 expect(exp({name:'VX'}).toEqual('Hello VX!');
			 </pre>
			 *
			 *
			 * @param {string} text The text with markup to interpolate.
			 * @param {boolean=} mustHaveExpression if set to true then the interpolation string must have
			 *    embedded expression in order to return an interpolation function. Strings with no
			 *    embedded expression will return null for the interpolation function.
			 * @returns {function(context)} an interpolation function which is used to compute the interpolated
			 *    string. The function has these parameters:
			 *
			 *    * `context`: an object against which any expressions embedded in the strings are evaluated
			 *      against.
			 *
			 */
			function $interpolate(text, mustHaveExpression) {
				var startIndex, endIndex, index = 0, parts = [], length = text.length, hasInterpolation = false, fn, exp, concat = [], isStatic = true;

				while (index < length) {
					if ((( startIndex = text.indexOf(startSymbol, index)) != -1) && (( endIndex = text.indexOf(endSymbol, startIndex + startSymbolLength)) != -1)) {
						if (index != startIndex)
							parts.push(text.substring(index, startIndex));
						parts.push( fn = parseExp(exp = text.substring(startIndex + startSymbolLength, endIndex)));
						fn.exp = exp;
						index = endIndex + endSymbolLength;
						if(!fn.$static)
							isStatic = false;
						hasInterpolation = true;
					} else {
						// we did not find anything, so we have to add the remainder to the parts array
						if (index != length)
							parts.push(text.substring(index));
						index = length;
					}
				}

				if (!( length = parts.length)) {
					// we added, nothing, must have been an empty string.
					parts.push('');
					length = 1;
				}

				if (!mustHaveExpression || hasInterpolation) {
					concat.length = length;
					fn = function(context, locals) {
						try {
							for (var i = 0, ii = length, part; i < ii; i++) {
								if ( typeof ( part = parts[i]) == 'function') {
									part = part(context, locals);
									if (part === null || part === undefined) {
										part = '';
									} else if ( typeof part != 'string') {
										part = toJson(part);
									}
								}
								concat[i] = part;
							}
							return concat.join('');
						} catch(err) {
							var newErr = vError(48, "$interpolate error! Can't interpolate: {0}\n{1}", text, err.toString());
							$log.error('Error while interpolating: ' + text + '\n', formatError(newErr));
							//$exceptionHandler(newErr);
						}
					};
					fn.$static = isStatic;
					fn.exp = text;
					fn.parts = parts;
					return fn;
				}
			}
			
			function parseExp(exp) {
				var isStatic = false;
				if(exp.charAt(0) === '#'){
					isStatic = true;
					if(exp.charAt(1) === '#'){
						exp = '$msg(' + exp.substring(2) + ')';
					} else {
						exp = '$field(' + exp.substring(1) + ')';
					}
				}
				var fn = $parse(exp);
				fn.$static = isStatic;
				return fn;
			}

			/**
			 * @vxdoc method
			 * @name v.$interpolate#startSymbol
			 * @methodOf v.$interpolate
			 * @description
			 * Symbol to denote the start of expression in the interpolated string. Defaults to `{{`.
			 *
			 * Use {@link v.$interpolateProvider#startSymbol $interpolateProvider#startSymbol} to change
			 * the symbol.
			 *
			 * @returns {string} start symbol.
			 */
			$interpolate.startSymbol = function() {
				return startSymbol;
			};
			/**
			 * @vxdoc method
			 * @name v.$interpolate#endSymbol
			 * @methodOf v.$interpolate
			 * @description
			 * Symbol to denote the end of expression in the interpolated string. Defaults to `}}`.
			 *
			 * Use {@link v.$interpolateProvider#endSymbol $interpolateProvider#endSymbol} to change
			 * the symbol.
			 *
			 * @returns {string} start symbol.
			 */
			$interpolate.endSymbol = function() {
				return endSymbol;
			};

			return $interpolate;
		}];

	}

	////////////////////////////////
	// $ControllerProvider
	///////////////////////////////
	/**
	 * @vxdoc object
	 * @name vx.$controllerProvider
	 * @description
	 * The {@link vx.$controller $controller service} is used by VX to create new
	 * controllers.
	 *
	 * This provider allows controller registration via the
	 * {@link vx.$controllerProvider#register register} method.
	 */
	function $ControllerProvider() {
		var controllers = {}, CNTRL_REG = /^(\S+)(\s+as\s+(\w+))?$/;

		/**
		 * @vxdoc function
		 * @name vx.$controllerProvider#register
		 * @methodOf vx.$controllerProvider
		 * @param {string} name Controller name
		 * @param {Function|Array} constructor Controller constructor fn (optionally decorated with DI
		 *    annotations in the array notation).
		 */
		this.register = function(name, constructor) {
			if (isObject(name)) {
				extend(controllers, name);
			} else {
				controllers[name] = constructor;
			}
		};

		this.$get = ['$injector', '$window',
		function($injector, $window) {
			/**
			 * @vxdoc function
			 * @name vx.$controller
			 * @requires $injector
			 *
			 * @param {Function|string} constructor If called with a function then it's considered to be the
			 *    controller constructor function. Otherwise it's considered to be a string which is used
			 *    to retrieve the controller constructor using the following steps:
			 *
			 *    * check if a controller with given name is registered via `$controllerProvider`
			 *    * check if evaluating the string on the current scope returns a constructor
			 *    * check `window[constructor]` on the global `window` object
			 *
			 * @param {Object} locals Injection locals for Controller.
			 * @return {Object} Instance of given controller.
			 *
			 * @description
			 * `$controller` service is responsible for instantiating controllers.
			 *
			 * It's just a simple call to {@link AUTO.$injector $injector}, but extracted into
			 * a service, so that one can override this service with {@link https://gist.github.com/1649788
			 * BC version}.
			 */
			return function(expression, locals) {
				var instance, match, constructor, identifier;

				if (isString(expression)) {
					match = expression.match(CNTRL_REG), constructor = match[1], identifier = match[3];
					expression = controllers.hasOwnProperty(constructor) ? controllers[constructor] : //
					getter(locals.$scope.$config, constructor, true) || getter(locals.$scope, constructor, true) || getter($window, constructor, true);
					assertArgFn(expression, constructor, true);
				}

				instance = $injector.instantiate(expression, locals);

				if (identifier) {
					if (!(locals && typeof locals.$scope == 'object')) {
						throw vError(36, "Cannot export controller '{0}' as '{1}'! No $scope object provided via `locals`.", constructor || expression.name, identifier);
					}
					locals.$scope[identifier] = instance;
				}

				return instance;
			};
		}];

	}

	////////////////////////////////
	// $CompileProvider
	///////////////////////////////
	/* ! VARIABLE/FUNCTION NAMING CONVENTIONS THAT APPLY TO THIS FILE!
	*
	* DOM-related variables:
	*
	* - "node" - DOM Node
	* - "element" - DOM Element or Node
	* - "$node" or "$element" - jqLite-wrapped node or element
	*
	*
	* Compiler related stuff:
	*
	* - "linkFn" - linking fn of a single directive
	* - "nodeLinkFn" - function that aggregates all linking fns for a particular node
	* - "childLinkFn" -  function that aggregates all linking fns for child nodes of a particular node
	* - "compositeLinkFn" - function that aggregates all linking fns for a compilation root (nodeList)
	*/

	var BOOLEAN_ATTR = {};
	forEach('multiple,selected,checked,disabled,readOnly,required,open'.split(','), function(value) {
		BOOLEAN_ATTR[lowercase(value)] = value;
	});
	var BOOLEAN_ELEMENTS = {};
	forEach('input,select,option,textarea,button,form,details'.split(','), function(value) {
		BOOLEAN_ELEMENTS[uppercase(value)] = true;
	});
	function getBooleanAttrName(element, name) {
		// check dom last since we will most likely fail on name
		var booleanAttr = BOOLEAN_ATTR[name.toLowerCase()];

		// booleanAttr is here twice to minimize DOM access
		return booleanAttr && BOOLEAN_ELEMENTS[element.nodeName] && booleanAttr;
	}

	/**
	 * Converts all accepted directives format into proper directive name.
	 * All of these will become 'myDirective':
	 *   my:DiRective
	 *   my-directive
	 *   x-my-directive
	 *   data-my:directive
	 *
	 * Also there is special case for Moz prefix starting with upper case letter.
	 * @param name Name to normalize
	 */
	var PREFIX_REGEXP = /^(x[\:\-_]|data[\:\-_])/i;
	function directiveNormalize(name) {
		return camelCase(name.replace(PREFIX_REGEXP, ''));
	}

	/**
	 * @vxdoc function
	 * @name vx.$compile
	 * @function
	 *
	 * @description
	 * Compiles a piece of HTML string or DOM into a template and produces a template function, which
	 * can then be used to link {@link vx.$rootScope.Scope scope} and the template together.
	 *
	 * The compilation is a process of walking the DOM tree and trying to match DOM elements to
	 * {@link vx.$compileProvider#directive directives}. For each match it
	 * executes corresponding template function and collects the
	 * instance functions into a single template function which is then returned.
	 *
	 * The template function can then be used once to produce the view or as it is the case with
	 * {@link vx.directive:vRepeat repeater} many-times, in which
	 * case each call results in a view that is a DOM clone of the original template.
	 *
	 <doc:example module="compile">
	 <doc:source>
	 <script>
	 // declare a new module, and inject the $compileProvider
	 vx.module('compile', [], function($compileProvider) {
	 // configure new 'compile' directive by passing a directive
	 // factory function. The factory function injects the '$compile'
	 $compileProvider.directive('compile', function($compile) {
	 // directive factory creates a link function
	 return function(scope, element, attrs) {
	 scope.$watch(
	 function(scope) {
	 // watch the 'compile' expression for changes
	 return scope.$eval(attrs.compile);
	 },
	 function(value) {
	 // when the 'compile' expression changes
	 // assign it into the current DOM
	 element.html(value);

	 // compile the new DOM and link it to the current
	 // scope.
	 // NOTE: we only compile .childNodes so that
	 // we don't get into infinite loop compiling ourselves
	 $compile(element.contents())(scope);
	 }
	 );
	 };
	 })
	 });

	 function Ctrl($scope) {
	 $scope.name = 'VX';
	 $scope.html = 'Hello {{name}}';
	 }
	 </script>
	 <div v-controller="Ctrl">
	 <input v-model="name"> <br>
	 <textarea v-model="html"></textarea> <br>
	 <div compile="html"></div>
	 </div>
	 </doc:source>
	 <doc:scenario>
	 it('should auto compile', function() {
	 expect(element('div[compile]').text()).toBe('Hello VX');
	 input('html').enter('{{name}}!');
	 expect(element('div[compile]').text()).toBe('VX!');
	 });
	 </doc:scenario>
	 </doc:example>

	 *
	 *
	 * @param {string|DOMElement} element Element or HTML string to compile into a template function.
	 * @param {function(vx.Scope[, cloneAttachFn]} transclude function available to directives.
	 * @param {number} maxPriority only apply directives lower then given priority (Only effects the
	 *                 root element(s), not their children)
	 * @returns {function(scope[, cloneAttachFn])} a link function which is used to bind template
	 * (a DOM element/tree) to a scope. Where:
	 *
	 *  * `scope` - A {@link vx.$rootScope.Scope Scope} to bind to.
	 *  * `cloneAttachFn` - If `cloneAttachFn` is provided, then the link function will clone the
	 *               `template` and call the `cloneAttachFn` function allowing the caller to attach the
	 *               cloned elements to the DOM document at the appropriate place. The `cloneAttachFn` is
	 *               called as: <br> `cloneAttachFn(clonedElement, scope)` where:
	 *
	 *      * `clonedElement` - is a clone of the original `element` passed into the compiler.
	 *      * `scope` - is the current scope with which the linking function is working with.
	 *
	 * Calling the linking function returns the element of the template. It is either the original element
	 * passed in, or the clone of the element if the `cloneAttachFn` is provided.
	 *
	 * After linking the view is not updated until after a call to $digest which typically is done by
	 * VX automatically.
	 *
	 * If you need access to the bound view, there are two ways to do it:
	 *
	 * - If you are not asking the linking function to clone the template, create the DOM element(s)
	 *   before you send them to the compiler and keep this reference around.
	 *   <pre>
	 *     var element = $compile('<p>{{total}}</p>')(scope);
	 *   </pre>
	 *
	 * - if on the other hand, you need the element to be cloned, the view reference from the original
	 *   example would not point to the clone, but rather to the original template that was cloned. In
	 *   this case, you can access the clone via the cloneAttachFn:
	 *   <pre>
	 *     var templateHTML = vx.element('<p>{{total}}</p>'),
	 *         scope = ....;
	 *
	 *     var clonedElement = $compile(templateHTML)(scope, function(clonedElement, scope) {
	 *       //attach the clone to DOM document at the right place
	 *     });
	 *
	 *     //now we have reference to the cloned DOM via `clone`
	 *   </pre>
	 *
	 *
	 * For information on how the compiler works, see the
	 * {@link guide/compiler VX HTML Compiler} section of the Developer Guide.
	 */
	$CompileProvider.$inject = ['$provide'];
	function $CompileProvider($provide) {
		var hasDirectives = {}, Suffix = 'Directive', COMMENT_DIRECTIVE_REGEXP = /^\s*directive\:\s*([\d\w\-_]+)\s+(.*)$/, //
		CLASS_DIRECTIVE_REGEXP = /(([\d\w\-_]+)(?:\:([^;]+))?;?)/, //
		urlSanitizationWhitelist = /^\s*(https?|ftp|mailto|file):/;

		/**
		 * @vxdoc function
		 * @name vx.$compileProvider#directive
		 * @methodOf vx.$compileProvider
		 * @function
		 *
		 * @description
		 * Register a new directives with the compiler.
		 *
		 * @param {string} name Name of the directive in camel-case. (ie <code>vBind</code> which will match as
		 *                <code>v-bind</code>).
		 * @param {function} directiveFactory An injectable directive factory function. See {@link guide/directive} for more
		 *                info.
		 * @returns {vx.$compileProvider} Self for chaining.
		 */
		this.directive = supportObject(registerDirective);

		function registerDirective(name, directiveFactory) {
			/*
			 TODO: directive FORMAT
			 directive {
			 priority:
			 name:
			 require:
			 restrict:
			 replace:
			 scope:
			 controller:
			 transclude:   //'element'
			 template:
			 templateUrl:
			 terminal:
			 compile:
			 link:
			 }
			 */
			assertArg(directiveFactory, 'directive');
			var replace;
			if (name.indexOf('*') === 0) {
				replace = true;
				name = name.substring(1);
			}
			if (replace || !hasDirectives.hasOwnProperty(name)) {
				hasDirectives[name] = [];
				$provide.factory(name + Suffix, ['$injector', /*'$exceptionHandler',*/'$log',
				function($injector, /*$exceptionHandler,*/$log) {
					var directives = [];
					forEach(hasDirectives[name], function(directiveFactory) {
						try {
							var directive = $injector.invoke(directiveFactory);
							if (isFunction(directive)) {
								directive = {
									compile : valueFn(directive)
								};
							} else if (!directive.compile && directive.link) {
								directive.compile = valueFn(directive.link);
							}
							directive.priority = directive.priority || 0;
							directive.name = directive.name || name;
							directive.require = directive.require || (directive.controller && directive.name);
							directive.restrict = directive.restrict || 'A';
							//'EACM'
							directives.push(directive);
						} catch (e) {
							$log.error(formatError(e));
							//$exceptionHandler(e);
						}
					});
					return directives;
				}]);

			}
			hasDirectives[name].push(directiveFactory);

			/*jshint validthis:true*/
			return this;
		}

		/**
		 * @vxdoc function
		 * @name v.$compileProvider#urlSanitizationWhitelist
		 * @methodOf v.$compileProvider
		 * @function
		 *
		 * @description
		 * Retrieves or overrides the default regular expression that is used for whitelisting of safe
		 * urls during a[href] sanitization.
		 *
		 * The sanitization is a security measure aimed at prevent XSS attacks via html links.
		 *
		 * Any url about to be assigned to a[href] via data-binding is first normalized and turned into an
		 * absolute url. Afterwards the url is matched against the `urlSanitizationWhitelist` regular
		 * expression. If a match is found the original url is written into the dom. Otherwise the
		 * absolute url is prefixed with `'unsafe:'` string and only then it is written into the DOM.
		 *
		 * @param {RegExp=} regexp New regexp to whitelist urls with.
		 * @returns {RegExp|v.$compileProvider} Current RegExp if called without value or self for
		 *    chaining otherwise.
		 */
		this.urlSanitizationWhitelist = function(regexp) {
			if (isDefined(regexp)) {
				urlSanitizationWhitelist = regexp;
				return this;
			}
			return urlSanitizationWhitelist;
		};

		this.$get = ['$injector', '$interpolate', /*$exceptionHandler',*/'$log', '$http', '$templateCache', '$parse', '$controller', '$rootScope', '$document', compiler];

		function compiler($injector, $interpolate, /*$exceptionHandler,*/$log, $http, $templateCache, $parse, $controller, $rootScope, $document) {
			/**
			 * @vxdoc object
			 * @name vx.$compile.directive.Attributes
			 * @description
			 *
			 * A shared object between directive compile / linking functions which contains normalized DOM element
			 * attributes. The the values reflect current binding state `{{ }}`. The normalization is needed
			 * since all of these are treated as equivalent in VX:
			 *
			 *          <span v:bind="a" v-bind="a" data-v-bind="a" x-v-bind="a">
			 */
			/**
			 * @vxdoc property
			 * @name vx.$compile.directive.Attributes#$attr
			 * @propertyOf vx.$compile.directive.Attributes
			 * @returns {object} A map of DOM element attribute names to the normalized name. This is
			 *          needed to do reverse lookup from normalized name back to actual name.
			 */
			/**
			 * @vxdoc function
			 * @name vx.$compile.directive.Attributes#$set
			 * @methodOf vx.$compile.directive.Attributes
			 * @function
			 *
			 * @description
			 * Set DOM element attribute value.
			 *
			 *
			 * @param {string} name Normalized element attribute name of the property to modify. The name is
			 *          revers translated using the {@link vx.$compile.directive.Attributes#$attr $attr}
			 *          property to the original name.
			 * @param {string} value Value to set the attribute to. The value can be an interpolated string.
			 */
			var Attributes = function(element, attr) {
				this.$$element = element;
				this.$attr = attr || {};
			};

			Attributes.prototype = {
				$normalize : directiveNormalize,
				/**
				 * Set a normalized attribute on the element in a way such that all directives
				 * can share the attribute. This function properly handles boolean attributes.
				 * @param {string} key Normalized key. (ie vAttribute)
				 * @param {string|boolean} value The value to set. If `null` attribute will be deleted.
				 * @param {boolean=} writeAttr If false, does not write the value to DOM element attribute.
				 *     Defaults to true.
				 * @param {string=} attrName Optional none normalized name. Defaults to key.
				 */
				$set : function(key, value, writeAttr, attrName) {
					var booleanKey = getBooleanAttrName(this.$$element[0], key), $$observers = this.$$observers, normalizedVal;

					if (booleanKey) {
						this.$$element.prop(key, value);
						attrName = booleanKey;
					}

					this[key] = value;

					// translate normalized key to actual key
					if (attrName) {
						this.$attr[key] = attrName;
					} else {
						attrName = this.$attr[key];
						if (!attrName) {
							this.$attr[key] = attrName = snake_case(key, '-');
						}
					}

					// sanitize a[href] values
					if (_nodeName(this.$$element[0]) === 'A' && key === 'href') {
						urlSanitizationNode.setAttribute('href', value);

						// href property always returns normalized absolute url, so we can match against that
						normalizedVal = urlSanitizationNode.href;
						if (!normalizedVal.match(urlSanitizationWhitelist)) {
							this[key] = value = 'unsafe:' + normalizedVal;
						}
					}

					if (writeAttr !== false) {
						if (value === null || value === undefined) {
							this.$$element.removeAttr(attrName);
						} else {
							this.$$element.attr(attrName, value);
						}
					}

					// fire observers
					if ($$observers)
						forEach($$observers[key], function(fn) {
							try {
								fn(value);
							} catch (e) {
								$log.error(formatError(e));
								//$exceptionHandler(e);
							}
						});
				},
				/**
				 * Observe an interpolated attribute.
				 * The observer will never be called, if given attribute is not interpolated.
				 *
				 * @param {string} key Normalized key. (ie vAttribute) .
				 * @param {function(*)} fn Function that will be called whenever the attribute value changes.
				 * @returns {function(*)} the `fn` Function passed in.
				 */
				$observe : function(key, fn) {
					var attrs = this, $$observers = (attrs.$$observers || (attrs.$$observers = {})), listeners = ($$observers[key] || ($$observers[key] = []));
					//XXX observe fn $watch in addAttrInterpolateDirective
					listeners.push(fn);
					/*$rootScope*/
					attrs.$$element.scope().$evalAsync(function() {
						if (!listeners.$$inter) {
							// no one registered attribute interpolation function, so lets call it manually
							fn(attrs[key]);
						}
					});
					return fn;
				}
			};

			var urlSanitizationNode = $document[0].createElement('a'), startSymbol = $interpolate.startSymbol(), endSymbol = $interpolate.endSymbol(), //
			denormalizeTemplate = (startSymbol == '{{' || endSymbol == '}}') ? identity : function denormalizeTemplate(template) {
				return template.replace(/\{\{/g, startSymbol).replace(/\}\}/g, endSymbol);
			}, V_ATTR_BINDING = /^vAttr[A-Z]/;

			return compile;

			//================================

			function compile($compileNodes, transcludeFn, maxPriority) {
				if (!( $compileNodes instanceof jqLite)) {
					// jquery always rewraps, where as we need to preserve the original selector so that we can modify it.
					$compileNodes = jqLite($compileNodes);
				}
				var tempParent = document.createDocumentFragment();
				// We can not compile top level text elements since text nodes can be merged and we will
				// not be able to attach scope data to them, so we will wrap them in <span>
				forEach($compileNodes, function(node, index) {
					if (node.nodeType == 3/* text node */ && node.nodeValue.match(/\S+/) /* non-empty */ ) {
						$compileNodes[index] = node = jqLite(node).wrap('<span></span>').parent()[0];
					}
				});
				var compositeLinkFn = compileNodes($compileNodes, transcludeFn, $compileNodes, maxPriority);
				return publicLinkFn;
				function publicLinkFn(scope, cloneConnectFn, scopeBinding) {
					assertArg(scope, 'scope');
					// important!!: we must call our jqLite.clone() since the jQuery one is trying to be smart
					// and sometimes changes the structure of the DOM.
					var $linkNode = cloneConnectFn ? jqLiteClone($compileNodes)// IMPORTANT!!!
					: $compileNodes;

					if (scopeBinding !== false) {
						// Attach scope only to non-text nodes.
						for (var i = 0, ii = $linkNode.length; i < ii; i++) {
							var node = $linkNode[i];
							if (node.nodeType == 1/* element */ || node.nodeType == 9 /* document */) {
								jqLite(node).data('$scope', scope);
							}
						}
						safeAddClass($linkNode, 'v-scope');
					}
					if (cloneConnectFn)
						cloneConnectFn($linkNode, scope);
					if (compositeLinkFn)
						compositeLinkFn(scope, $linkNode, $linkNode);

					return $linkNode;
				}

			}

			function safeAddClass($element, className) {
				try {
					$element.addClass(className);
				} catch(e) {
					// ignore, since it means that we are trying to set class on
					// SVG element, where class name is read-only.
				}
			}

			/**
			 * Compile function matches each node in nodeList against the directives. Once all directives
			 * for a particular node are collected their compile functions are executed. The compile
			 * functions return values - the linking functions - are combined into a composite linking
			 * function, which is the a linking function for the node.
			 *
			 * @param {NodeList} nodeList an array of nodes or NodeList to compile
			 * @param {function(vx.Scope[, cloneAttachFn]} transcludeFn A linking function, where the
			 *        scope argument is auto-generated to the new child of the transcluded parent scope.
			 * @param {DOMElement=} $rootElement If the nodeList is the root of the compilation tree then the
			 *        rootElement must be set the jqLite collection of the compile root. This is
			 *        needed so that the jqLite collection items can be replaced with widgets.
			 * @param {number=} max directive priority
			 * @returns {?function} A composite linking function of all of the matched directives or null.
			 */
			function compileNodes(nodeList, transcludeFn, $rootElement, maxPriority) {
				var linkFns = [], nodeLinkFn, childLinkFn, directives, attrs, linkFnFound;

				for (var i = 0; i < nodeList.length; i++) {
					attrs = new Attributes();
					// we must always refer to nodeList[i] since the nodes can be replaced underneath us.
					directives = collectDirectives(nodeList[i], [], attrs, i === 0 ? maxPriority : undefined);
					nodeLinkFn = (directives.length) ? applyDirectivesToNode(directives, nodeList[i], attrs, transcludeFn, $rootElement) : null;
					childLinkFn = (nodeLinkFn && nodeLinkFn.terminal || !nodeList[i].childNodes || !nodeList[i].childNodes.length)//
					? null//
					: compileNodes(nodeList[i].childNodes, nodeLinkFn ? nodeLinkFn.transclude : transcludeFn);

					linkFns.push(nodeLinkFn);
					linkFns.push(childLinkFn);
					linkFnFound = (linkFnFound || nodeLinkFn || childLinkFn);
				}

				// return a linking function if we have found anything, null otherwise
				return linkFnFound ? compositeLinkFn : null;

				function compositeLinkFn(scope, nodeList, $rootElement, boundTranscludeFn) {
					var nodeLinkFn, childLinkFn, node, childScope, childTranscludeFn, i, ii, n;
					var fn1 = function(transcludeFn) {
						return function(cloneFn) {
							var transcludeScope = scope.$new();
							transcludeScope.$$transcluded = true;
							return transcludeFn(transcludeScope, cloneFn).bind('$destroy', bind(transcludeScope, transcludeScope.$destroy));
						};
					};
					// copy nodeList so that linking doesn't break due to live list updates.
					var stableNodeList = [];
					for ( i = 0, ii = nodeList.length; i < ii; i++) {
						stableNodeList.push(nodeList[i]);
					}
					for ( i = 0, n = 0, ii = linkFns.length; i < ii; n++) {
						node = stableNodeList[n];
						nodeLinkFn = linkFns[i++];
						childLinkFn = linkFns[i++];
						if (nodeLinkFn) {
							if (nodeLinkFn.scope) {
								//new scope in Controller, others child scope create by include/view/switch/repeat
								// isObject $new isolate
								childScope = scope.$new(isObject(nodeLinkFn.scope));
								jqLite(node).data('$scope', childScope);
							} else {
								childScope = scope;
							}
							childTranscludeFn = nodeLinkFn.transclude;
							if (childTranscludeFn || (!boundTranscludeFn && transcludeFn)) {
								nodeLinkFn(childLinkFn, childScope, node, $rootElement, fn1(childTranscludeFn || transcludeFn));
							} else {
								nodeLinkFn(childLinkFn, childScope, node, undefined, boundTranscludeFn);
							}
						} else if (childLinkFn) {
							childLinkFn(scope, node.childNodes, undefined, boundTranscludeFn);
						}
					}
				}

			}

			/**
			 * Looks for directives on the given node and adds them to the directive collection which is sorted.
			 *
			 * @param node Node to search
			 * @param directives An array to which the directives are added to. This array is sorted before
			 *        the function returns.
			 * @param attrs The shared attrs object which is used to populate the normalized attributes.
			 * @param {number=} maxPriority Max directive priority.
			 */
			function collectDirectives(node, directives, attrs, maxPriority) {
				var nodeType = node.nodeType, attrsMap = attrs.$attr, match, className, nodeName = _nodeName(node);

				switch(nodeType) {
					case 1:
						/* Element */
						// use the node name: <directive>
						addDirective(directives, directiveNormalize(_nodeName(node).toLowerCase()), 'E', maxPriority);

						// iterate over the attributes
						for (var attr, name, nName, vAttrName, value, nAttrs = node.attributes, j = 0, jj = nAttrs && nAttrs.length; j < jj; j++) {
							var attrStartName;
							var attrEndName;
							var index;

							attr = nAttrs[j];
							name = attr.name;

							//XXX in IE, other attributes not specified in node.attributes
							// jimmy**** in IE 6/7 input's value is unspecified
							if (!attr.specified) {
								if (!msie || msie > 7)
									continue;
								if (name === 'type') {
									// for IE6/7 unsupported html5 input type, eg: url/number/email and etc
									value = node.getAttribute('type');
									if (nodeName === 'BUTTON') {
										// IE 6/7 button default type is Button, it is not standard!!!
										value = 'submit';
									}
								} else if (name === 'value')
									value = trim(attr.value);
								else
									continue;
							} else {
								value = trim((msie && name === 'href') ? decodeURIComponent(node.getAttribute(name, 2)) : attr.value);
							}

							// support vAttr attribute binding
							vAttrName = directiveNormalize(name);
							if (V_ATTR_BINDING.test(vAttrName)) {
								name = vAttrName.substr(5).toLowerCase();
							}
							if (( index = vAttrName.lastIndexOf('Start')) != -1 && index == vAttrName.length - 5) {
								attrStartName = name;
								attrEndName = name.substr(0, name.length - 5) + 'end';
								name = name.substr(0, name.length - 6);
							}
							nName = directiveNormalize(name.toLowerCase());
							attrsMap[nName] = name;
							attrs[nName] = value;
							if (getBooleanAttrName(node, nName)) {
								// presence means true
								attrs[nName] = value = true;
							}
							if (value)
								addAttrInterpolateDirective(node, directives, value, nName);
							addDirective(directives, nName, 'A', maxPriority, attrStartName, attrEndName);
						}

						// use class as directive
						className = node.className;
						if (isString(className) && className !== '') {
							/*jshint boss:true*/
							while ( match = CLASS_DIRECTIVE_REGEXP.exec(className)) {
								nName = directiveNormalize(match[2]);
								if (addDirective(directives, nName, 'C', maxPriority)) {
									attrs[nName] = trim(match[3]);
								}
								className = className.substr(match.index + match[0].length);
							}
						}
						break;
					case 3:
						/* Text Node */
						addTextInterpolateDirective(directives, node.nodeValue);
						break;
					case 8:
						/* Comment */
						try {
							match = COMMENT_DIRECTIVE_REGEXP.exec(node.nodeValue);
							if (match) {
								nName = directiveNormalize(match[1]);
								if (addDirective(directives, nName, 'M', maxPriority)) {
									attrs[nName] = trim(match[2]);
								}
							}
						} catch (e) {
							// turns out that under some circumstances IE9 throws errors when one attempts to read comment's node value.
							// Just ignore it and continue. (Can't seem to reproduce in test case.)
						}
						break;
				}

				directives.sort(byPriority);
				return directives;

				/**
				 * Sorting function for bound directives.
				 */
				function byPriority(a, b) {
					return b.priority - a.priority;
				}

				/**
				 * looks up the directive and decorates it with exception handling and proper parameters. We
				 * call this the boundDirective.
				 *
				 * @param {string} name name of the directive to look up.
				 * @param {string} location The directive must be found in specific format.
				 *   String containing any of theses characters:
				 *
				 *   * `E`: element name
				 *   * `A': attribute
				 *   * `C`: class
				 *   * `M`: comment
				 * @returns true if directive was added.
				 */
				function addDirective(tDirectives, name, location, maxPriority, startAttrName, endAttrName) {
					var match = null;
					if (hasDirectives.hasOwnProperty(name)) {
						for (var directive, directives = $injector.get(name + Suffix), i = 0, ii = directives.length; i < ii; i++) {
							try {
								directive = directives[i];
								if ((maxPriority === undefined || maxPriority > directive.priority) && directive.restrict.indexOf(location) != -1) {
									if (startAttrName) {
										directive = inherit(directive, {
											$$start : startAttrName,
											$$end : endAttrName
										});
									}
									tDirectives.push(directive);
									match = directive;
								}
							} catch(e) {
								$log.error(formatError(e));
								//$exceptionHandler(e);
							}
						}
					}
					return match;
				}

				function addTextInterpolateDirective(directives, text) {
					var interpolateFn = $interpolate(text, true);
					if (interpolateFn) {
						directives.push({
							priority : 0,
							compile : valueFn(function textInterpolateLinkFn(scope, node) {
								if(interpolateFn.$static) {
									node[0].nodeValue = interpolateFn(scope);
									return;
								}
								var parent = node.parent(), bindings = parent.data('$binding') || [];
								bindings.push(interpolateFn);
								parent.data('$binding', bindings);
								safeAddClass(parent, 'v-binding');
								scope.$watch(interpolateFn, function interpolateFnWatchAction(value) {
									node[0].nodeValue = value;
								});
							})
						});
					}
				}

				function addAttrInterpolateDirective(node, directives, value, name) {
					var interpolateFn = $interpolate(value, true);
					// no interpolation found -> ignore
					if (!interpolateFn)
						return;
					directives.push({
						priority : 100,
						compile : valueFn(function attrInterpolateLinkFn(scope, element, attr) {
							if(interpolateFn.$static) {
								attr.$set(name, interpolateFn(scope));
								return;
							}
							
							var $$observers = (attr.$$observers || (attr.$$observers = {}));
							// we need to interpolate again, in case the attribute value has been updated
							// (e.g. by another directive's compile function)
							interpolateFn = $interpolate(attr[name], true);
							// if attribute was updated so that there is no interpolation going on we don't want to
							// register any observers
							if (!interpolateFn)
								return;

							attr[name] = interpolateFn(scope);
							($$observers[name] || ($$observers[name] = [])).$$inter = true;
							(attr.$$observers && attr.$$observers[name].$$scope || scope).$watch(interpolateFn, function interpolateFnWatchAction(value) {
								attr.$set(name, value);
							});
						})
					});
				}

			}

			/**
			 * Given a node with an directive-start it collects all of the siblings until it find directive-end.
			 * @param node
			 * @param attrStart
			 * @param attrEnd
			 * @returns {*}
			 */
			function groupScan(node, attrStart, attrEnd) {
				var nodes = [];
				var depth = 0;
				if (attrStart && node.hasAttribute && node.hasAttribute(attrStart)) {
					var startNode = node;
					do {
						if (!node) {
							throw vError(37, "Unterminated attribute, found '{0}' but no matching '{1}' found.", attrStart, attrEnd);
						}
						if (node.hasAttribute(attrStart))
							depth++;
						if (node.hasAttribute(attrEnd))
							depth--;
						nodes.push(node);
						node = node.nextSibling;
					} while (depth > 0);
				} else {
					nodes.push(node);
				}
				return jqLite(nodes);
			}

			/**
			 * Wrapper for linking function which converts normal linking function into a grouped
			 * linking function.
			 * @param linkFn
			 * @param attrStart
			 * @param attrEnd
			 * @returns {Function}
			 */
			function groupElementsLinkFnWrapper(linkFn, attrStart, attrEnd) {
				return function(scope, element, attrs, controllers) {
					element = groupScan(element[0], attrStart, attrEnd);
					return linkFn(scope, element, attrs, controllers);
				};
			}

			/**
			 * Once the directives have been collected their compile functions are executed. This method
			 * is responsible for inlining directive templates as well as terminating the application
			 * of the directives if the terminal directive has been reached.
			 *
			 * @param {Array} directives Array of collected directives to execute their compile function.
			 *        this needs to be pre-sorted by priority order.
			 * @param {Node} compileNode The raw DOM node to apply the compile functions to
			 * @param {Object} templateAttrs The shared attribute function
			 * @param {function(vx.Scope[, cloneAttachFn]} transcludeFn A linking function, where the
			 *        scope argument is auto-generated to the new child of the transcluded parent scope.
			 * @param {JQLite} jqCollection If we are working on the root of the compile tree then this
			 *        argument has the root jqLite array so that we can replace nodes on it.
			 * @returns linkFn
			 */
			function applyDirectivesToNode(directives, compileNode, templateAttrs, transcludeFn, jqCollection) {
				var terminalPriority = -Number.MAX_VALUE, preLinkFns = [], postLinkFns = [], newScopeDirective = null, //
				newIsolateScopeDirective = null, templateDirective = null, //
				$compileNode = templateAttrs.$$element = jqLite(compileNode), // add $$element to attr object
				directive, directiveName, $template, transcludeDirective, childTranscludeFn = transcludeFn, controllerDirectives, linkFn, directiveValue;

				// executes all directives on the current element
				for (var i = 0, ii = directives.length; i < ii; i++) {
					directive = directives[i];
					var attrStart = directive.$$start;
					var attrEnd = directive.$$end;

					// collect multiblock sections
					if (attrStart) {
						$compileNode = groupScan(compileNode, attrStart, attrEnd);
					}
					$template = undefined;

					if (terminalPriority > directive.priority) {
						break;
						// prevent further processing of directives
					}

					/*jshint boss:true*/
					if ( directiveValue = directive.scope) {
						assertNoDuplicate('isolated scope', newIsolateScopeDirective, directive, $compileNode);
						if (isObject(directiveValue)) {
							safeAddClass($compileNode, 'v-isolate-scope');
							newIsolateScopeDirective = directive;
						}
						safeAddClass($compileNode, 'v-scope');
						newScopeDirective = newScopeDirective || directive;
					}
					directiveName = directive.name;

					if ( directiveValue = directive.controller) {
						controllerDirectives = controllerDirectives || {};
						assertNoDuplicate("'" + directiveName + "' controller", controllerDirectives[directiveName], directive, $compileNode);
						controllerDirectives[directiveName] = directive;
					}

					if ( directiveValue = directive.transclude) {
						assertNoDuplicate('transclusion', transcludeDirective, directive, $compileNode);
						transcludeDirective = directive;
						terminalPriority = directive.priority;
						if (directiveValue == 'element') {
							$template = groupScan(compileNode, attrStart, attrEnd);
							$compileNode = templateAttrs.$$element = jqLite(document.createComment(' ' + directiveName + ': ' + templateAttrs[directiveName] + ' '));
							compileNode = $compileNode[0];
							replaceWith(jqCollection, jqLite(sliceArgs($template)), compileNode);
							childTranscludeFn = compile($template, transcludeFn, terminalPriority);
						} else {
							//XXX need shivForIE for unknown element below IE8
							$template = jqLite(jqLiteClone(compileNode)).contents();
							$compileNode.html('');
							// clear contents
							childTranscludeFn = compile($template, transcludeFn);
						}
					}

					if (directive.template) {
						assertNoDuplicate('template', templateDirective, directive, $compileNode);
						templateDirective = directive;
						directiveValue = (isFunction(directive.template)) ? directive.template($compileNode, templateAttrs) : directive.template;

						directiveValue = denormalizeTemplate(directiveValue);

						if (directive.replace) {
							$template = jqLite('<div>' + trim(directiveValue) + '</div>').contents();
							compileNode = $template[0];

							if ($template.length != 1 || compileNode.nodeType !== 1) {
								throw vError(38, "Template for directive '{0}' must have exactly one root element.", directiveName);
							}
							replaceWith(jqCollection, $compileNode, compileNode);
							var newTemplateAttrs = {
								$attr : {}
							};

							// combine directives from the original node and from the template:
							// - take the array of directives for this element
							// - split it into two parts, those that were already applied and those that weren't
							// - collect directives from the template, add them to the second group and sort them
							// - append the second group with new directives to the first group
							directives = directives.concat(collectDirectives(compileNode, directives.splice(i + 1, directives.length - (i + 1)), newTemplateAttrs));
							mergeTemplateAttributes(templateAttrs, newTemplateAttrs);
							ii = directives.length;
						} else {
							$compileNode.html(directiveValue);
						}
					}

					if (directive.templateUrl) {
						assertNoDuplicate('template', templateDirective, directive, $compileNode);
						templateDirective = directive;
						//replace nodeLinkFn
						nodeLinkFn = compileTemplateUrl(directives.splice(i, directives.length - i), nodeLinkFn, $compileNode, templateAttrs, jqCollection, directive.replace, childTranscludeFn);
						ii = directives.length;
					} else if (directive.compile) {
						try {
							linkFn = directive.compile($compileNode, templateAttrs, childTranscludeFn);
							if (isFunction(linkFn)) {
								addLinkFns(null, linkFn, attrStart, attrEnd);
							} else if (linkFn) {
								addLinkFns(linkFn.pre, linkFn.post, attrStart, attrEnd);
							}
						} catch (e) {
							$log.error(formatError(e), startingTag($compileNode));
							//$exceptionHandler(e, startingTag($compileNode));
						}
					}

					if (directive.terminal) {
						nodeLinkFn.terminal = true;
						terminalPriority = Math.max(terminalPriority, directive.priority);
					}

				}
				nodeLinkFn.scope = newScopeDirective && newScopeDirective.scope;
				nodeLinkFn.transclude = transcludeDirective && childTranscludeFn;

				// IE leak?
				compileNode = $compileNode = $template = jqCollection = null;

				// might be normal or delayed nodeLinkFn depending on if templateUrl is present
				return nodeLinkFn;

				function assertNoDuplicate(what, previousDirective, directive, element) {
					if (previousDirective) {
						throw vError(39, 'Multiple directives [{0}, {1}] asking for {2} on: {3}', previousDirective.name, directive.name, what, startingTag(element));
					}
				}

				//-----------------------------------------------------

				function addLinkFns(pre, post, attrStart, attrEnd) {
					if (pre) {
						if (attrStart)
							pre = groupElementsLinkFnWrapper(pre, attrStart, attrEnd);
						pre.require = directive.require;
						preLinkFns.push(pre);
					}
					if (post) {
						if (attrStart)
							post = groupElementsLinkFnWrapper(post, attrStart, attrEnd);
						post.require = directive.require;
						postLinkFns.push(post);
					}
				}

				function nodeLinkFn(childLinkFn, scope, linkNode, $rootElement, boundTranscludeFn) {
					var attrs, $element, i, ii, linkFn, controller;

					if (compileNode === linkNode) {
						attrs = templateAttrs;
					} else {
						attrs = shallowCopy(templateAttrs, new Attributes(jqLite(linkNode), templateAttrs.$attr));
					}
					$element = attrs.$$element;

					if (newIsolateScopeDirective) {
						var LOCAL_REGEXP = /^\s*([@=&])(\??)\s*(\w*)\s*$/;

						var parentScope = scope.$parent || scope;

						forEach(newIsolateScopeDirective.scope, function(definition, scopeName) {
							var match = definition.match(LOCAL_REGEXP) || [], attrName = match[3] || scopeName, optional = (match[2] == '?'), mode = match[1], // @, =, or &
							lastValue, parentGet, parentSet;

							scope.$$isolateBindings[scopeName] = mode + attrName;
							switch (mode) {
								case '@':
									// simple set scope
									attrs.$observe(attrName, function(value) {
										scope[scopeName] = value;
									});
									attrs.$$observers[attrName].$$scope = parentScope;
									if (attrs[attrName]) {
										// If the attribute has been provided then we trigger an interpolation to ensure the value is there for use in the link fn
										scope[scopeName] = $interpolate(attrs[attrName])(parentScope);
									}
									break;
								case '=':
									if (optional && !attrs[attrName]) {
										return;
									}
									// sync with parent
									parentGet = $parse(attrs[attrName]);
									parentSet = parentGet.assign ||
									function() {
										// reset the change, or we will throw this exception on every $digest
										lastValue = scope[scopeName] = parentGet(parentScope);
										throw vError(40, "Expression '{0}' used with directive '{1}' is non-assignable!", attrs[attrName], newIsolateScopeDirective.name);
									};

									lastValue = scope[scopeName] = parentGet(parentScope);
									scope.$watch(function parentValueWatch() {
										var parentValue = parentGet(parentScope);
										if (parentValue !== scope[scopeName]) {
											// we are out of sync and need to copy
											if (parentValue !== lastValue) {
												// parent changed and it has precedence
												lastValue = scope[scopeName] = parentValue;
											} else {
												// if the parent can be assigned then do so
												parentSet(parentScope, parentValue = lastValue = scope[scopeName]);
											}
										}
										return parentValue;
									});
									break;
								case '&':
									// get from parent
									parentGet = $parse(attrs[attrName]);
									scope[scopeName] = function(locals) {
										return parentGet(parentScope, locals);
									};
									break;
								default:
									throw vError(41, "Invalid isolate scope definition for directive '{0}'. Definition: {... {1}: '{2}' ...}", newIsolateScopeDirective.name, scopeName, definition);
							}
						});
					}

					if (controllerDirectives) {
						forEach(controllerDirectives, function(directive) {
							var locals = {
								$scope : scope,
								$element : $element,
								$attrs : attrs,
								$transclude : boundTranscludeFn
							};
							controller = directive.controller;
							if (controller == '@') {
								controller = attrs[directive.name];
							} else if (controller == '@@') {
								controller = attrs[directive.name] || $element.controller('vViewport').$id + '_setup';
							}

							$element.data('$' + directive.name + 'Controller', $controller(controller, locals));
						});
					}

					// PRELINKING
					for ( i = 0, ii = preLinkFns.length; i < ii; i++) {
						try {
							linkFn = preLinkFns[i];
							linkFn(scope, $element, attrs, linkFn.require && getControllers(linkFn.require, $element));
						} catch (e) {
							$log.error(formatError(e), startingTag($element));
							//$exceptionHandler(e, startingTag($element));
						}
					}

					// RECURSION
					if (childLinkFn)
						childLinkFn(scope, linkNode.childNodes, undefined, boundTranscludeFn);

					// POSTLINKING
					for ( i = 0, ii = postLinkFns.length; i < ii; i++) {
						try {
							linkFn = postLinkFns[i];
							linkFn(scope, $element, attrs, linkFn.require && getControllers(linkFn.require, $element));
						} catch (e) {
							$log.error(formatError(e), startingTag($element));
							//$exceptionHandler(e, startingTag($element));
						}
					}
				}

				function getControllers(require, $element) {
					var value, retrievalMethod = 'data', optional = false;
					if (isString(require)) {
						while (( value = require.charAt(0)) == '^' || value == '?') {
							require = require.substr(1);
							if (value == '^') {
								retrievalMethod = 'inheritedData';
							}
							optional = optional || value == '?';
						}
						value = $element[retrievalMethod]('$' + require + 'Controller');
						if (!value && !optional) {
							throw vError(42, "Controller '{0}', required by directive '{1}', can't be found!", require, directiveName);
						}
						return value;
					} else if (isArray(require)) {
						value = [];
						forEach(require, function(require) {
							value.push(getControllers(require, $element));
						});
					}
					return value;
				}

				function compileTemplateUrl(directives, beforeTemplateNodeLinkFn, $compileNode, tAttrs, $rootElement, replace, childTranscludeFn) {
					var linkQueue = [], afterTemplateNodeLinkFn, afterTemplateChildLinkFn, beforeTemplateCompileNode = $compileNode[0], origAsyncDirective = directives.shift(),
					// The fact that we have to copy and patch the directive seems wrong!
					derivedSyncDirective = extend({}, origAsyncDirective, {
						controller : null,
						templateUrl : null,
						transclude : null,
						scope : null
					}), templateUrl = (isFunction(origAsyncDirective.templateUrl)) ? origAsyncDirective.templateUrl($compileNode, tAttrs) : origAsyncDirective.templateUrl;

					$compileNode.html('');

					//XXX need $scope and ajaxPort???
					$http.get(templateUrl, {
						cache : $templateCache
					}).success(function(content) {
						var compileNode, tempTemplateAttrs, $template;
						content = denormalizeTemplate(content);

						if (replace) {
							$template = jqLite('<div>' + trim(content) + '</div>').contents();
							compileNode = $template[0];

							if ($template.length != 1 || compileNode.nodeType !== 1) {
								throw vError(43, "Template for directive '{0}' must have exactly one root element. Template: {1}", origAsyncDirective.name, templateUrl);
							}
							tempTemplateAttrs = {
								$attr : {}
							};
							replaceWith($rootElement, $compileNode, compileNode);
							collectDirectives(compileNode, directives, tempTemplateAttrs);
							mergeTemplateAttributes(tAttrs, tempTemplateAttrs);
						} else {
							compileNode = beforeTemplateCompileNode;
							$compileNode.html(content);
						}

						directives.unshift(derivedSyncDirective);
						afterTemplateNodeLinkFn = applyDirectivesToNode(directives, compileNode, tAttrs, childTranscludeFn);
						afterTemplateChildLinkFn = compileNodes($compileNode[0].childNodes, childTranscludeFn);

						while (linkQueue.length) {
							var scope = linkQueue.shift(), beforeTemplateLinkNode = linkQueue.shift(), linkRootElement = linkQueue.shift(), controller = linkQueue.shift(), linkNode = compileNode;

							if (beforeTemplateLinkNode !== beforeTemplateCompileNode) {
								// it was cloned therefore we have to clone as well.
								linkNode = jqLiteClone(compileNode);
								replaceWith(linkRootElement, jqLite(beforeTemplateLinkNode), linkNode);
							}

							/*jshint loopfunc:true*/
							afterTemplateNodeLinkFn(function() {
								beforeTemplateNodeLinkFn(afterTemplateChildLinkFn, scope, linkNode, $rootElement, controller);
							}, scope, linkNode, $rootElement, controller);
						}
						linkQueue = null;
					}).error(function(response, code, headers, config) {
						throw vError(44, 'Failed to load template: {0}', config.url);
					});
					return function delayedNodeLinkFn(ignoreChildLinkFn, scope, node, rootElement, controller) {
						if (linkQueue) {
							linkQueue.push(scope);
							linkQueue.push(node);
							linkQueue.push(rootElement);
							linkQueue.push(controller);
						} else {
							afterTemplateNodeLinkFn(function() {
								beforeTemplateNodeLinkFn(afterTemplateChildLinkFn, scope, node, rootElement, controller);
							}, scope, node, rootElement, controller);
						}
					};
				}

				/**
				 * When the element is replaced with HTML template then the new attributes
				 * on the template need to be merged with the existing attributes in the DOM.
				 * The desired effect is to have both of the attributes present.
				 *
				 * @param {object} dst destination attributes (original DOM)
				 * @param {object} src source attributes (from the directive template)
				 */
				function mergeTemplateAttributes(dst, src) {
					var srcAttr = src.$attr, dstAttr = dst.$attr, $element = dst.$$element;
					// reapply the old attributes to the new element
					forEach(dst, function(value, key) {
						if (key.charAt(0) != '$') {
							if (src[key]) {
								value += (key === 'style' ? ';' : ' ') + src[key];
							}
							dst.$set(key, value, true, srcAttr[key]);
						}
					});
					// copy the new attributes on the old attrs object
					forEach(src, function(value, key) {
						if (key == 'class') {
							safeAddClass($element, value);
							dst['class'] = (dst['class'] ? dst['class'] + ' ' : '') + value;
						} else if (key == 'style') {
							$element.attr('style', $element.attr('style') + ';' + value);
						} else if (key.charAt(0) != '$' && !dst.hasOwnProperty(key)) {
							dst[key] = value;
							dstAttr[key] = srcAttr[key];
						}
					});
				}

				/**
				 * This is a special jqLite.replaceWith, which can replace items which
				 * have no parents, provided that the containing jqLite collection is provided.
				 *
				 * @param {JqLite=} $rootElement The root of the compile tree. Used so that we can replace nodes
				 *    in the root of the tree.
				 * @param {JqLite} elementsToRemove The jqLite element which we are going to replace. We keep the shell,
				 *    but replace its DOM node reference.
				 * @param {Node} newNode The new DOM node.
				 */
				function replaceWith($rootElement, elementsToRemove, newNode) {
					var firstElementToRemove = elementsToRemove[0], removeCount = elementsToRemove.length, parent = firstElementToRemove.parentNode, i, ii;

					if ($rootElement) {
						for ( i = 0, ii = $rootElement.length; i < ii; i++) {
							if ($rootElement[i] == firstElementToRemove) {
								$rootElement[i++] = newNode;
								for (var j = i, j2 = j + removeCount - 1, jj = $rootElement.length; j < jj; j++, j2++) {
									if (j2 < jj) {
										$rootElement[j] = $rootElement[j2];
									} else {
										delete $rootElement[j];
									}
								}
								$rootElement.length -= removeCount - 1;
								break;
							}
						}
					}

					if (parent) {
						parent.replaceChild(newNode, firstElementToRemove);
					}
					var fragment = document.createDocumentFragment();
					fragment.appendChild(firstElementToRemove);
					newNode[jqLite.expando] = firstElementToRemove[jqLite.expando];
					//***jimmy fix class
					safeAddClass(jqLite(newNode), firstElementToRemove.className);

					for (var k = 1, kk = elementsToRemove.length; k < kk; k++) {
						var element = elementsToRemove[k];
						jqLite(element).remove();
						// must do this way to clean up expando
						fragment.appendChild(element);
						delete elementsToRemove[k];
					}

					elementsToRemove[0] = newNode;
					elementsToRemove.length = 1;

				}

			}

		}

	}

	/**
	 * Closure compiler type information
	 */
	function nodesetLinkFn(
	/* vx.Scope */scope,
	/* NodeList */nodeList,
	/* Element */rootElement,
	/* function(Function) */boundTranscludeFn) {
	}

	function nodeLinkFn(
	/* nodesetLinkFn */nodesetLinkFn,
	/* vx.Scope */scope,
	/* Node */node,
	/* Element */rootElement,
	/* function(Function) */boundTranscludeFn) {
	}

	////////////////////////////////
	// $RootScopeProvider
	///////////////////////////////

	/**
	 * DESIGN NOTES
	 *
	 * The design decisions behind the scope are heavily favored for speed and memory consumption.
	 *
	 * The typical use of scope is to watch the expressions, which most of the time return the same
	 * value as last time so we optimize the operation.
	 *
	 * Closures construction is expensive in terms of speed as well as memory:
	 *   - No closures, instead use prototypical inheritance for API
	 *   - Internal state needs to be stored on scope directly, which means that private state is
	 *     exposed as $$____ properties
	 *
	 * Loop operations are optimized by using while(count--) { ... }
	 *   - this means that in order to keep the same order of execution as addition we have to add
	 *     items to the array at the beginning (shift) instead of at the end (push)
	 *
	 * Child scopes are created and removed often
	 *   - Using an array would be slow since inserts in middle are expensive so we use linked list
	 *
	 * There are few watches then a lot of observers. This is why you don't want the observer to be
	 * implemented in the same way as watch. Watch requires return of initialization function which
	 * are expensive to construct.
	 */

	/**
	 * @vxdoc object
	 * @name vx.$rootScopeProvider
	 * @description
	 *
	 * Provider for the $rootScope service.
	 */

	/**
	 * @vxdoc function
	 * @name vx.$rootScopeProvider#digestTtl
	 * @methodOf vx.$rootScopeProvider
	 * @description
	 *
	 * Sets the number of digest iterations the scope should attempt to execute before giving up and
	 * assuming that the model is unstable.
	 *
	 * The current default is 10 iterations.
	 *
	 * @param {number} limit The number of digest iterations.
	 */

	/**
	 * @vxdoc object
	 * @name vx.$rootScope
	 * @description
	 *
	 * Every application has a single root {@link vx.$rootScope.Scope scope}.
	 * All other scopes are child scopes of the root scope. Scopes provide mechanism for watching the model and provide
	 * event processing life-cycle. See {@link guide/scope developer guide on scopes}.
	 */
	function $RootScopeProvider() {
		var TTL = 10, digestTraced;
		this.digestTtl = function(value) {
			if (arguments.length) {
				TTL = value;
			}
			return TTL;
		};

		this.traceDigest = function(yes) {
			digestTraced = !!yes;
		};

		this.$get = [/*'$injector', *//*'$exceptionHandler', */'$log', '$parse', 'dateFilter', '$window', '$locale', '$rootElement', scopeFactory];

		function scopeFactory(/*$injector, *//*$exceptionHandler, */$log, $parse, dateFilter, $window, $locale, $rootElement) {

			/**
			 * @vxdoc function
			 * @name vx.$rootScope.Scope
			 *
			 * @description
			 * A root scope can be retrieved using the {@link vx.$rootScope $rootScope} key from the
			 * {@link AUTO.$injector $injector}. Child scopes are created using the
			 * {@link vx.$rootScope.Scope#$new $new()} method. (Most scopes are created automatically when
			 * compiled HTML template is executed.)
			 *
			 * Here is a simple scope snippet to show how you can interact with the scope.
			 * <pre>
			 vx.injector(['v']).invoke(function($rootScope) {
			 var scope = $rootScope.$new();
			 scope.salutation = 'Hello';
			 scope.name = 'World';

			 expect(scope.greeting).toEqual(undefined);

			 scope.$watch('name', function() {
			 scope.greeting = scope.salutation + ' ' + scope.name + '!';
			 }); // initialize the watch

			 expect(scope.greeting).toEqual(undefined);
			 scope.name = 'Misko';
			 // still old value, since watches have not been called yet
			 expect(scope.greeting).toEqual(undefined);

			 scope.$digest(); // fire all  the watches
			 expect(scope.greeting).toEqual('Hello Misko!');
			 });
			 * </pre>
			 *
			 * # Inheritance
			 * A scope can inherit from a parent scope, as in this example:
			 * <pre>
			 var parent = $rootScope;
			 var child = parent.$new();

			 parent.salutation = "Hello";
			 child.name = "World";
			 expect(child.salutation).toEqual('Hello');

			 child.salutation = "Welcome";
			 expect(child.salutation).toEqual('Welcome');
			 expect(parent.salutation).toEqual('Hello');
			 * </pre>
			 *
			 *
			 * @param {Object.<string, function()>=} providers Map of service factory which need to be provided
			 *     for the current scope. Defaults to {@link v}.
			 * @param {Object.<string, *>=} instanceCache Provides pre-instantiated services which should
			 *     append/override services provided by `providers`. This is handy when unit-testing and having
			 *     the need to override a default service.
			 * @returns {Object} Newly created scope.
			 *
			 */
			function Scope() {
				this.$id = nextUid(scopeId);
				this.$$phase = this.$$watchers = this.$$nextSibling = this.$$prevSibling = this.$$childHead = this.$$childTail = this.$parent = null;
				this['this'] = this.$root = this;
				this.$$destroyed = false;
				this.$$asyncQueue = [];
				this.$$listeners = {};
				this.$$isolateBindings = {};

				this.$repaint = repaintFactory($rootElement);

				this.$window = $window;
				this.$vx = vx;
				this.$now = function(fmt) {
					if (fmt === undefined || fmt === false)
						return now();
					if (fmt === true)
						return dateFilter(now(), 'yyyy-MM-ddTHH:mm:ss.sssZ');
					return dateFilter(now(), fmt);
				};

				this.$field = function(name) {
					return $locale.FIELDS[name] || name;
				};
				this.$msg = function(name) {
					return $locale.MESSAGES[name] || name;
				};
			}

			/**
			 * @vxdoc property
			 * @name vx.$rootScope.Scope#$id
			 * @propertyOf vx.$rootScope.Scope
			 * @returns {number} Unique scope ID (monotonically increasing alphanumeric sequence) useful for
			 *   debugging.
			 */
			Scope.prototype = {
				/**
				 * @vxdoc function
				 * @name vx.$rootScope.Scope#$new
				 * @methodOf vx.$rootScope.Scope
				 * @function
				 *
				 * @description
				 * Creates a new child {@link vx.$rootScope.Scope scope}.
				 *
				 * The parent scope will propagate the {@link vx.$rootScope.Scope#$digest $digest()} and
				 * {@link vx.$rootScope.Scope#$digest $digest()} events. The scope can be removed from the scope
				 * hierarchy using {@link vx.$rootScope.Scope#$destroy $destroy()}.
				 *
				 * {@link vx.$rootScope.Scope#$destroy $destroy()} must be called on a scope when it is desired for
				 * the scope and its child scopes to be permanently detached from the parent and thus stop
				 * participating in model change detection and listener notification by invoking.
				 *
				 * @param {boolean} isolate if true then the scope does not prototypically inherit from the
				 *         parent scope. The scope is isolated, as it can not see parent scope properties.
				 *         When creating widgets it is useful for the widget to not accidentally read parent
				 *         state.
				 *
				 * @returns {Object} The newly created child scope.
				 *
				 */
				$new : function(isolate) {
					var Child, child;
					if (isolate) {
						child = new Scope();
						child.$root = this.$root;
					} else {
						Child = function() {
						};
						// should be anonymous; This is so that when the minifier munges
						// the name it does not become random set of chars. These will then show up as class
						// name in the debugger.
						Child.prototype = this;
						child = new Child();
						child.$id = nextUid(scopeId);
					}
					child['this'] = child;
					child.$$listeners = {};
					child.$parent = this;
					child.$$watchers = child.$$nextSibling = child.$$childHead = child.$$childTail = null;
					child.$$prevSibling = this.$$childTail;
					if (this.$$childHead) {
						this.$$childTail.$$nextSibling = child;
						this.$$childTail = child;
					} else {
						this.$$childHead = this.$$childTail = child;
					}

					return child;
				},
				/**
				 * @vxdoc function
				 * @name vx.$rootScope.Scope#$watch
				 * @methodOf vx.$rootScope.Scope
				 * @function
				 *
				 * @description
				 * Registers a `listener` callback to be executed whenever the `watchExpression` changes.
				 *
				 * - The `watchExpression` is called on every call to {@link vx.$rootScope.Scope#$digest $digest()} and
				 *   should return the value which will be watched. (Since {@link vx.$rootScope.Scope#$digest $digest()}
				 *   reruns when it detects changes the `watchExpression` can execute multiple times per
				 *   {@link vx.$rootScope.Scope#$digest $digest()} and should be idempotent.)
				 * - The `listener` is called only when the value from the current `watchExpression` and the
				 *   previous call to `watchExpression` are not equal (with the exception of the initial run,
				 *   see below). The inequality is determined according to
				 *   {@link vx.equals} function. To save the value of the object for later comparison, the
				 *   {@link vx.copy} function is used. It also means that watching complex options will
				 *   have adverse memory and performance implications.
				 * - The watch `listener` may change the model, which may trigger other `listener`s to fire. This
				 *   is achieved by rerunning the watchers until no changes are detected. The rerun iteration
				 *   limit is 10 to prevent an infinite loop deadlock.
				 *
				 *
				 * If you want to be notified whenever {@link vx.$rootScope.Scope#$digest $digest} is called,
				 * you can register a `watchExpression` function with no `listener`. (Since `watchExpression`
				 * can execute multiple times per {@link vx.$rootScope.Scope#$digest $digest} cycle when a change is
				 * detected, be prepared for multiple calls to your listener.)
				 *
				 * After a watcher is registered with the scope, the `listener` fn is called asynchronously
				 * (via {@link vx.$rootScope.Scope#$evalAsync $evalAsync}) to initialize the
				 * watcher. In rare cases, this is undesirable because the listener is called when the result
				 * of `watchExpression` didn't change. To detect this scenario within the `listener` fn, you
				 * can compare the `newVal` and `oldVal`. If these two values are identical (`===`) then the
				 * listener was called due to initialization.
				 *
				 *
				 * # Example
				 * <pre>
				 // let's assume that scope was dependency injected as the $rootScope
				 var scope = $rootScope;
				 scope.name = 'misko';
				 scope.counter = 0;

				 expect(scope.counter).toEqual(0);
				 scope.$watch('name', function(newValue, oldValue) { scope.counter = scope.counter + 1; });
				 expect(scope.counter).toEqual(0);

				 scope.$digest();
				 // no variable change
				 expect(scope.counter).toEqual(0);

				 scope.name = 'adam';
				 scope.$digest();
				 expect(scope.counter).toEqual(1);
				 * </pre>
				 *
				 *
				 *
				 * @param {(function()|string)} watchExpression Expression that is evaluated on each
				 *    {@link vx.$rootScope.Scope#$digest $digest} cycle. A change in the return value triggers a
				 *    call to the `listener`.
				 *
				 *    - `string`: Evaluated as {@link guide/expression expression}
				 *    - `function(scope)`: called with current `scope` as a parameter.
				 * @param {(function()|string)=} listener Callback called whenever the return value of
				 *   the `watchExpression` changes.
				 *
				 *    - `string`: Evaluated as {@link guide/expression expression}
				 *    - `function(newValue, oldValue, scope)`: called with current and previous values as parameters.
				 *
				 * @param {boolean=} objectEquality Compare object for equality rather than for reference.
				 * @returns {function()} Returns a deregistration function for this listener.
				 */
				$watch : function(watchExp, listener, objectEquality, runFirst) {
					var scope = this, get = compileToFn(watchExp, 'watch'), array = scope.$$watchers, watcher = {
						fn : listener,
						last : initWatchVal,
						get : get,
						exp : watchExp,
						eq : !!objectEquality
					};

					// in the case user pass string, we need to compile it, do we really need this ?
					if (!isFunction(listener)) {
						var listenFn = compileToFn(listener || noop, 'listener');
						watcher.fn = function(newVal, oldVal, scope) {
							listenFn(scope);
						};
					}

					if ( typeof watchExp == 'string' && get.constant) {
						var originalFn = watcher.fn;
						watcher.fn = function(newVal, oldVal, scope) {
							originalFn.call(this, newVal, oldVal, scope);
							arrayRemove(array, watcher);
						};
					}

					if (!array) {
						array = scope.$$watchers = [];
					}
					// we use unshift since we use a while loop in $digest for speed.
					// the while loop reads in reverse order.
					array.unshift(watcher);

					if (runFirst) {
						var value = watcher.get(scope);
						watcher.last = watcher.eq ? copy(value) : value;
						watcher.fn(value, null, scope);
					}

					return function() {
						arrayRemove(array, watcher);
					};
				},

				/**
				 * @vxdoc function
				 * @name vx.$rootScope.Scope#$watchCollection
				 * @methodOf vx.$rootScope.Scope
				 * @function
				 *
				 * @description
				 * Shallow watches the properties of an object and fires whenever any of the properties change
				 * (for arrays this implies watching the array items, for object maps this implies watching the properties).
				 * If a change is detected the `listener` callback is fired.
				 *
				 * - The `obj` collection is observed via standard $watch operation and is examined on every call to $digest() to
				 *   see if any items have been added, removed, or moved.
				 * - The `listener` is called whenever anything within the `obj` has changed. Examples include adding new items
				 *   into the object or array, removing and moving items around.
				 *
				 *
				 * # Example
				 * <pre>
				 $scope.names = ['igor', 'matias', 'misko', 'james'];
				 $scope.dataCount = 4;

				 $scope.$watchCollection('names', function(newNames, oldNames) {
				 $scope.dataCount = newNames.length;
				 });

				 expect($scope.dataCount).toEqual(4);
				 $scope.$digest();

				 //still at 4 ... no changes
				 expect($scope.dataCount).toEqual(4);

				 $scope.names.pop();
				 $scope.$digest();

				 //now there's been a change
				 expect($scope.dataCount).toEqual(3);
				 * </pre>
				 *
				 *
				 * @param {string|Function(scope)} obj Evaluated as {@link guide/expression expression}. The expression value
				 *    should evaluate to an object or an array which is observed on each
				 *    {@link vx.$rootScope.Scope#$digest $digest} cycle. Any shallow change within the collection will trigger
				 *    a call to the `listener`.
				 *
				 * @param {function(newCollection, oldCollection, scope)} listener a callback function that is fired with both
				 *    the `newCollection` and `oldCollection` as parameters.
				 *    The `newCollection` object is the newly modified data obtained from the `obj` expression and the
				 *    `oldCollection` object is a copy of the former collection data.
				 *    The `scope` refers to the current scope.
				 *
				 * @returns {function()} Returns a de-registration function for this listener. When the de-registration function is executed
				 * then the internal watch operation is terminated.
				 */
				$watchCollection : function(obj, listener, runFirst) {
					var self = this;
					var oldValue;
					var newValue;
					var changeDetected = 0;
					var objGetter = $parse(obj);
					var internalArray = [];
					var internalObject = {};
					var oldLength = 0;

					function $watchCollectionWatch() {
						newValue = objGetter(self);
						var newLength, key;

						if (!isObject(newValue)) {
							if (oldValue !== newValue) {
								oldValue = newValue;
								changeDetected++;
							}
						} else if (isArrayLike(newValue)) {
							if (oldValue !== internalArray) {
								// we are transitioning from something which was not an array into array.
								oldValue = internalArray;
								oldLength = oldValue.length = 0;
								changeDetected++;
							}

							newLength = newValue.length;

							if (oldLength !== newLength) {
								// if lengths do not match we need to trigger change notification
								changeDetected++;
								oldValue.length = oldLength = newLength;
							}
							// copy the items to oldValue and look for changes.
							for (var i = 0; i < newLength; i++) {
								if (oldValue[i] !== newValue[i]) {
									changeDetected++;
									oldValue[i] = newValue[i];
								}
							}
						} else {
							if (oldValue !== internalObject) {
								// we are transitioning from something which was not an object into object.
								oldValue = internalObject = {};
								oldLength = 0;
								changeDetected++;
							}
							// copy the items to oldValue and look for changes.
							newLength = 0;
							for (key in newValue) {
								if (newValue.hasOwnProperty(key)) {
									newLength++;
									if (oldValue.hasOwnProperty(key)) {
										if (oldValue[key] !== newValue[key]) {
											changeDetected++;
											oldValue[key] = newValue[key];
										}
									} else {
										oldLength++;
										oldValue[key] = newValue[key];
										changeDetected++;
									}
								}
							}
							if (oldLength > newLength) {
								// we used to have more keys, need to find them and destroy them.
								changeDetected++;
								for (key in oldValue) {
									if (oldValue.hasOwnProperty(key) && !newValue.hasOwnProperty(key)) {
										oldLength--;
										delete oldValue[key];
									}
								}
							}
						}
						return changeDetected;
					}

					function $watchCollectionAction() {
						listener(newValue, oldValue, self);
					}

					return this.$watch($watchCollectionWatch, $watchCollectionAction, false, runFirst);
				},

				/**
				 * @vxdoc function
				 * @name vx.$rootScope.Scope#$digest
				 * @methodOf vx.$rootScope.Scope
				 * @function
				 *
				 * @description
				 * Processes all of the {@link vx.$rootScope.Scope#$watch watchers} of the current scope and its children.
				 * Because a {@link vx.$rootScope.Scope#$watch watcher}'s listener can change the model, the
				 * `$digest()` keeps calling the {@link vx.$rootScope.Scope#$watch watchers} until no more listeners are
				 * firing. This means that it is possible to get into an infinite loop. This function will throw
				 * `'Maximum iteration limit exceeded.'` if the number of iterations exceeds 10.
				 *
				 * Usually you don't call `$digest()` directly in
				 * {@link vx.directive:vController controllers} or in
				 * {@link vx.$compileProvider#directive directives}.
				 * Instead a call to {@link vx.$rootScope.Scope#$apply $apply()} (typically from within a
				 * {@link vx.$compileProvider#directive directives}) will force a `$digest()`.
				 *
				 * If you want to be notified whenever `$digest()` is called,
				 * you can register a `watchExpression` function  with {@link vx.$rootScope.Scope#$watch $watch()}
				 * with no `listener`.
				 *
				 * You may have a need to call `$digest()` from within unit-tests, to simulate the scope
				 * life-cycle.
				 *
				 * # Example
				 * <pre>
				 var scope = ...;
				 scope.name = 'misko';
				 scope.counter = 0;

				 expect(scope.counter).toEqual(0);
				 scope.$watch('name', function(newValue, oldValue) {
				 scope.counter = scope.counter + 1;
				 });
				 expect(scope.counter).toEqual(0);

				 scope.$digest();
				 // no variable change
				 expect(scope.counter).toEqual(0);

				 scope.name = 'adam';
				 scope.$digest();
				 expect(scope.counter).toEqual(1);
				 * </pre>
				 *
				 */
				$digest : function(cause) {
					var watch, value, last, watchers, asyncQueue = this.$$asyncQueue, length, dirty, ttl = TTL, next, //
					current, target = this, watchLog = [], logIdx, logMsg;

					beginPhase(target, '$digest');
					var startMs = now();
					try {
						do {// "while dirty" loop
							dirty = false;
							current = target;

							while (asyncQueue.length) {
								//try {
								current.$eval(asyncQueue.shift());
								//} catch (e) {
								//  $log.error(e);
								//	$exceptionHandler(e);
								//}
							}

							do {// "traverse the scopes" loop
								if (( watchers = current.$$watchers)) {
									// process our watches
									length = watchers.length;
									while (length--) {
										//try {
										watch = watchers[length];
										// Most common watches are on primitives, in which case we can short
										// circuit it with === operator, only when === fails do we use .equals
										if (( value = watch.get(current)) !== ( last = watch.last) && !(watch.eq ? equals(value, last) : //
										( typeof value == 'number' && typeof last == 'number' && isNaN(value) && isNaN(last)))) {
											dirty = true;
											watch.last = watch.eq ? copy(value) : value;
											watch.fn(value, ((last === initWatchVal) ? value : last), current);
											if (ttl < 5) {
												logIdx = 4 - ttl;
												if (!watchLog[logIdx])
													watchLog[logIdx] = [];
												logMsg = (isFunction(watch.exp)) ? 'fn: ' + (watch.exp.name || watch.exp.toString()) : watch.exp;
												logMsg += '; newVal: ' + toJson(value) + '; oldVal: ' + toJson(last);
												watchLog[logIdx].push(logMsg);
											}
										}
										//} catch (e) {
										//  $log.error(e);
										//	$exceptionHandler(e);
										//}
									}
								}

								// Insanity Warning : scope depth-first traversal
								// yes, this code is a bit crazy, but it works and we have tests to prove it!
								// this piece should be kept in sync with the traversal in $broadcast
								if (!( next = (current.$$childHead || (current !== target && current.$$nextSibling)))) {
									while (current !== target && !( next = current.$$nextSibling)) {
										current = current.$parent;
									}
								}
							} while ((current = next));

							if (dirty && !(ttl--)) {
								clearPhase(target);
								throw vError(45, '{0} $digest() iterations reached. Aborting!\nWatchers fired in the last 5 iterations: {1}', TTL, toJson(watchLog));
							}
						} while (dirty || asyncQueue.length);

					} finally {
						if (digestTraced) {
							$log.debug('$digest (' + (now() - startMs) + 'ms, iteration: ' + (TTL - ttl + 1) + ') in scope ' + this.$id + //
							(this.hasOwnProperty('$$viewport') ? ' for viewport ' + this.$$viewport : '') + ( cause ? ' by ' + cause : ''));
						}
						clearPhase(target);

						target.$repaint();
					}
				},
				/**
				 * @vxdoc event
				 * @name vx.$rootScope.Scope#$destroy
				 * @eventOf vx.$rootScope.Scope
				 * @eventType broadcast on scope being destroyed
				 *
				 * @description
				 * Broadcasted when a scope and its children are being destroyed.
				 */

				/**
				 * @vxdoc function
				 * @name vx.$rootScope.Scope#$destroy
				 * @methodOf vx.$rootScope.Scope
				 * @function
				 *
				 * @description
				 * Removes the current scope (and all of its children) from the parent scope. Removal implies
				 * that calls to {@link vx.$rootScope.Scope#$digest $digest()} will no longer
				 * propagate to the current scope and its children. Removal also implies that the current
				 * scope is eligible for garbage collection.
				 *
				 * The `$destroy()` is usually used by directives such as
				 * {@link vx.directive:vRepeat vRepeat} for managing the
				 * unrolling of the loop.
				 *
				 * Just before a scope is destroyed a `$destroy` event is broadcasted on this scope.
				 * Application code can register a `$destroy` event handler that will give it chance to
				 * perform any necessary cleanup.
				 */
				$destroy : function() {
					if ($rootScope == this || this.$$destroyed)
						return;
					// we can't remove the root node;
					var parent = this.$parent;

					this.$broadcast('$destroy');
					this.$$destroyed = true;

					var target = this, current = target, next = target, i;
					//down while you can, then up and next sibling or up and next sibling until back at root
					do {
						current = next;
						delete current.$$applied;
						// for viewport appliedScope.
						delete current.$$watchers;
						delete current.$$asyncQueue;
						delete current.$$listeners;
						delete current.$$isolateBindings;

						for (i in current) {
							if (current.hasOwnProperty(i) && i.substr(0, 2) !== '$$' && i !== '$parent' && i !== '$root' && i !== '$id') {
								delete current[i];
							}
						}

						// Insanity Warning : scope depth-first traversal
						// yes, this code is a bit crazy, but it works and we have tests to prove it!
						// this piece should be kept in sync with the traversal in $digest
						if (!( next = (current.$$childHead || (current !== target && current.$$nextSibling)))) {
							while (current !== target && !( next = current.$$nextSibling)) {
								current = current.$parent;
							}
						}
					} while ((current = next));

					if (parent.$$childHead == this)
						parent.$$childHead = this.$$nextSibling;
					if (parent.$$childTail == this)
						parent.$$childTail = this.$$prevSibling;
					if (this.$$prevSibling)
						this.$$prevSibling.$$nextSibling = this.$$nextSibling;
					if (this.$$nextSibling)
						this.$$nextSibling.$$prevSibling = this.$$prevSibling;

					// This is bogus code that works around Chrome's GC leak
					this.$parent = this.$$nextSibling = this.$$prevSibling = this.$$childHead = this.$$childTail = null;

				},
				/**
				 * @vxdoc function
				 * @name vx.$rootScope.Scope#$eval
				 * @methodOf vx.$rootScope.Scope
				 * @function
				 *
				 * @description
				 * Executes the `expression` on the current scope returning the result. Any exceptions in the
				 * expression are propagated (uncaught). This is useful when evaluating vx expressions.
				 *
				 * # Example
				 * <pre>
				 var scope = vx.$rootScope.Scope();
				 scope.a = 1;
				 scope.b = 2;

				 expect(scope.$eval('a+b')).toEqual(3);
				 expect(scope.$eval(function(scope){ return scope.a + scope.b; })).toEqual(3);
				 * </pre>
				 *
				 * @param {(string|function())=} expression An vx expression to be executed.
				 *
				 *    - `string`: execute using the rules as defined in  {@link guide/expression expression}.
				 *    - `function(scope)`: execute the function with the current `scope` parameter.
				 *
				 * @returns {*} The result of evaluating the expression.
				 */
				$eval : function(expr, locals) {
					return $parse(expr)(this, locals);
				},
				/**
				 * @vxdoc function
				 * @name vx.$rootScope.Scope#$evalAsync
				 * @methodOf vx.$rootScope.Scope
				 * @function
				 *
				 * @description
				 * Executes the expression on the current scope at a later point in time.
				 *
				 * The `$evalAsync` makes no guarantees as to when the `expression` will be executed, only that:
				 *
				 *   - it will execute in the current script execution context (before any DOM rendering).
				 *   - at least one {@link vx.$rootScope.Scope#$digest $digest cycle} will be performed after
				 *     `expression` execution.
				 *
				 * Any exceptions from the execution of the expression are forwarded to the
				 * {@link vx.$exceptionHandler $exceptionHandler} service.
				 *
				 * @param {(string|function())=} expression An vx expression to be executed.
				 *
				 *    - `string`: execute using the rules as defined in  {@link guide/expression expression}.
				 *    - `function(scope)`: execute the function with the current `scope` parameter.
				 *
				 */
				$evalAsync : function(expr) {
					this.$$asyncQueue.push(expr);
				},
				/**
				 * @vxdoc function
				 * @name vx.$rootScope.Scope#$apply
				 * @methodOf vx.$rootScope.Scope
				 * @function
				 *
				 * @description
				 * `$apply()` is used to execute an expression in vx from outside of the vx framework.
				 * (For example from browser DOM events, setTimeout, XHR or third party libraries).
				 * Because we are calling into the vx framework we need to perform proper scope life-cycle
				 * of {@link vx.$exceptionHandler exception handling},
				 * {@link vx.$rootScope.Scope#$digest executing watches}.
				 *
				 * ## Life cycle
				 *
				 * # Pseudo-Code of `$apply()`
				 * <pre>
				 function $apply(expr) {
				 try {
				 return $eval(expr);
				 } catch (e) {
				 $exceptionHandler(e);
				 } finally {
				 $root.$digest();
				 }
				 }
				 * </pre>
				 *
				 *
				 * Scope's `$apply()` method transitions through the following stages:
				 *
				 * 1. The {@link guide/expression expression} is executed using the
				 *    {@link vx.$rootScope.Scope#$eval $eval()} method.
				 * 2. Any exceptions from the execution of the expression are forwarded to the
				 *    {@link vx.$exceptionHandler $exceptionHandler} service.
				 * 3. The {@link vx.$rootScope.Scope#$watch watch} listeners are fired immediately after the expression
				 *    was executed using the {@link vx.$rootScope.Scope#$digest $digest()} method.
				 *
				 *
				 * @param {(string|function())=} exp An vx expression to be executed.
				 *
				 *    - `string`: execute using the rules as defined in {@link guide/expression expression}.
				 *    - `function(scope)`: execute the function with current `scope` parameter.
				 *
				 * @returns {*} The result of evaluating the expression.
				 */
				$apply : function(expr, cause) {
					try {
						beginPhase(this, '$apply');
						return this.$eval(expr);
					} catch (e) {
						$log.error(formatError(e));
						//$exceptionHandler(e);
					} finally {
						clearPhase(this);
						try {
							var appliedScope = this.$$applied || $rootScope;
							appliedScope.$digest(cause);
						} catch (e) {
							$log.error(formatError(e));
							//$exceptionHandler(e);
							//throw e;
						}
					}
				},
				/**
				 * @vxdoc function
				 * @name vx.$rootScope.Scope#$on
				 * @methodOf vx.$rootScope.Scope
				 * @function
				 *
				 * @description
				 * Listens on events of a given type. See {@link vx.$rootScope.Scope#$emit $emit} for discussion of
				 * event life cycle.
				 *
				 * @param {string} name Event name to listen on.
				 * @param {function(event, args...)} listener Function to call when the event is emitted.
				 * @returns {function()} Returns a deregistration function for this listener.
				 *
				 * The event listener function format is: `function(event, args...)`. The `event` object passed into the
				 * listener has the following attributes
				 *
				 *   - `targetScope` - `{Scope}`: the scope on which the event was `$emit`-ed or `$broadcast`-ed.
				 *   - `currentScope` - `{Scope}`: the current scope which is handling the event.
				 *   - `name` - `{string}`: Name of the event.
				 *   - `stopPropagation` - `{function=}`: calling `stopPropagation` function will cancel further event propagation
				 *     (available only for events that were `$emit`-ed).
				 *   - `preventDefault` - `{function}`: calling `preventDefault` sets `defaultPrevented` flag to true.
				 *   - `defaultPrevented` - `{boolean}`: true if `preventDefault` was called.
				 */
				$on : function(name, listener) {
					var namedListeners = this.$$listeners[name];
					if (!namedListeners) {
						this.$$listeners[name] = namedListeners = [];
					}
					namedListeners.push(listener);
					return function() {
						namedListeners[indexOf(namedListeners, listener)] = null;
					};
				},
				/**
				 * @vxdoc function
				 * @name vx.$rootScope.Scope#$emit
				 * @methodOf vx.$rootScope.Scope
				 * @function
				 *
				 * @description
				 * Dispatches an event `name` upwards through the scope hierarchy notifying the
				 * registered {@link vx.$rootScope.Scope#$on} listeners.
				 *
				 * The event life cycle starts at the scope on which `$emit` was called. All
				 * {@link vx.$rootScope.Scope#$on listeners} listening for `name` event on this scope get notified.
				 * Afterwards, the event traverses upwards toward the root scope and calls all registered
				 * listeners along the way. The event will stop propagating if one of the listeners cancels it.
				 *
				 * Any exception emitted from the {@link vx.$rootScope.Scope#$on listeners} will be passed
				 * onto the {@link vx.$exceptionHandler $exceptionHandler} service.
				 *
				 * @param {string} name Event name to emit.
				 * @param {...*} args Optional set of arguments which will be passed onto the event listeners.
				 * @return {Object} Event object, see {@link vx.$rootScope.Scope#$on}
				 */
				$emit : function(name, args) {
					var empty = [], namedListeners, scope = this, stopPropagation = false, event = {
						name : name,
						targetScope : scope,
						stopPropagation : function() {
							stopPropagation = true;
						},
						preventDefault : function() {
							event.defaultPrevented = true;
						},
						defaultPrevented : false
					}, listenerArgs = concat([event], arguments, 1), i, length;

					do {
						namedListeners = scope.$$listeners[name] || empty;
						event.currentScope = scope;
						for ( i = 0, length = namedListeners.length; i < length; i++) {
							// if listeners were deregistered, defragment the array
							if (!namedListeners[i]) {
								namedListeners.splice(i, 1);
								i--;
								length--;
								continue;
							}
							try {
								_fastInvoke(namedListeners[i], null, listenerArgs);
								if (stopPropagation)
									return event;
							} catch (e) {
								$log.error(formatError(e));
								//$exceptionHandler(e);
							}
						}
						//traverse upwards
						scope = scope.$parent;
					} while (scope);
					return event;
				},
				/**
				 * @vxdoc function
				 * @name vx.$rootScope.Scope#$broadcast
				 * @methodOf vx.$rootScope.Scope
				 * @function
				 *
				 * @description
				 * Dispatches an event `name` downwards to all child scopes (and their children) notifying the
				 * registered {@link vx.$rootScope.Scope#$on} listeners.
				 *
				 * The event life cycle starts at the scope on which `$broadcast` was called. All
				 * {@link vx.$rootScope.Scope#$on listeners} listening for `name` event on this scope get notified.
				 * Afterwards, the event propagates to all direct and indirect scopes of the current scope and
				 * calls all registered listeners along the way. The event cannot be canceled.
				 *
				 * Any exception emitted from the {@link vx.$rootScope.Scope#$on listeners} will be passed
				 * onto the {@link vx.$exceptionHandler $exceptionHandler} service.
				 *
				 * @param {string} name Event name to broadcast.
				 * @param {...*} args Optional set of arguments which will be passed onto the event listeners.
				 * @return {Object} Event object, see {@link vx.$rootScope.Scope#$on}
				 */
				$broadcast : function(name, args) {
					var target = this, current = target, next = target, event = {
						name : name,
						targetScope : target,
						preventDefault : function() {
							event.defaultPrevented = true;
						},
						defaultPrevented : false
					}, listenerArgs = concat([event], arguments, 1), listeners, i, length;

					//down while you can, then up and next sibling or up and next sibling until back at root
					do {
						current = next;
						event.currentScope = current;
						listeners = current.$$listeners[name] || [];
						for ( i = 0, length = listeners.length; i < length; i++) {
							// if listeners were deregistered, defragment the array
							if (!listeners[i]) {
								listeners.splice(i, 1);
								i--;
								length--;
								continue;
							}

							try {
								_fastInvoke(listeners[i], null, listenerArgs);
							} catch(e) {
								$log.error(formatError(e));
								//$exceptionHandler(e);
							}
						}
						// Insanity Warning : scope depth-first traversal
						// yes, this code is a bit crazy, but it works and we have tests to prove it!
						// this piece should be kept in sync with the traversal in $digest
						if (!( next = (current.$$childHead || (current !== target && current.$$nextSibling)))) {
							while (current !== target && !( next = current.$$nextSibling)) {
								current = current.$parent;
							}
						}
					} while ((current = next));
					return event;
				}
			};
			var $rootScope = new Scope();

			return $rootScope;
			// -------------------------------------------

			function beginPhase(scope, phase) {
				if (scope.$$phase) {
					throw vError(46, '{0} already in progress', scope.$$phase);
				}
				scope.$$phase = phase;
			}

			function clearPhase(scope) {
				scope.$$phase = null;
			}

			function compileToFn(exp, name) {
				var fn = $parse(exp);
				assertArgFn(fn, name);
				return fn;
			}

			/**
			 * function used as an initial value for watchers.
			 * because it's unique we can easily tell it apart from other values
			 */
			function initWatchVal() {
			}

		}

	}

	function injectRemote(el, locals, expr, submit, $$remote) {
		locals = locals || {};
		if (/\$remote\./.test(expr)) {
			var $remote = el.data('$remote');
			if (!$remote) {
				$remote = $$remote(el, submit);
				el.data('$remote', $remote);
			}
			locals.$remote = $remote;
		}
		return locals;
	}

	// $$Remote service
	function $$RemoteProvider() {
		var getFailData, errorTag = '$error', callbacks = {},useEncrypt = false;

		this.setErrorCallback = function(fn) {
			// fn(response.data, response.status, response.headers, config);
			// if error return error object, otherwise return null
			getFailData = fn;
		};

		this.setErrorTag = function(n) {
			errorTag = n;
		};

		this.addCallback = function(name, callback) {
			// fn(data, ...)
			callbacks[name] = callback;
		};
		this.useEncrypt = function(flag){
			useEncrypt = !!flag;
		};
		// this.setEncryptKey = function(key){
			// encryptKey = key || encryptKey;
		// };

		this.$get = ['$http', '$targets', '$log', remoteFactory];

		function remoteFactory($http, $targets, $log) {

			// override $http in viewport
			function wrapHttp(scope, ajaxPort, refer) {
				function $config(config) {
					return extend(config || {}, {
						$scope : scope,
						ajaxPort : ajaxPort,
						$referer : refer
					});
				}

				var $$http = function(config) {
					return $http($config(config));
				};
				$$http.get = function(url, config) {
					return $http.get(url, $config(config));
				};
				$$http['delete'] = function(url, config) {
					return $http['delete'](url, $config(config));
				};
				$$http.head = function(url, config) {
					return $http.head(url, $config(config));
				};
				$$http.jsonp = function(url, config) {
					return $http.jsonp(url, $config(config));
				};
				$$http.post = function(url, data, config) {
					return $http.post(url, data, $config(config));
				};
				$$http.put = function(url, data, config) {
					return $http.put(url, data, $config(config));
				};

				return $$http;
			}

			return function($element, submit, ajaxPort) {
				var view = $element.controller('vViewport');
				var scope = view && view.$activeElement.scope() || $element.scope();
				var refer = view && view.$rootUrl || '/';

				$element = null;

				return {
					$http : function() {
						return view && wrapHttp(scope, ajaxPort, refer) || $http;
					},
					get : function(url, data, okTag, config) {
						return withParams('get', url, data, okTag, config);
					},
					'delete' : function(url, data, okTag, config) {
						return withParams('delete', url, data, okTag, config);
					},
					head : function(url, data, okTag, config) {
						return withParams('head', url, data, okTag, config);
					},
					jsonp : function(url, data, okTag, config) {
						return withParams('jsonp', url, data, okTag, config);
					},
					post : function(url, data, okTag, config) {
						return withNoParams('post', url, data, okTag, config);
					},
					put : function(url, data, okTag, config) {
						return withNoParams('put', url, data, okTag, config);
					}
				};

				function withParams(name, url, data, okTag, config) {
					var params;
					if (isString(data) || isFunction(data)) {
						okTag = data;
						config = okTag;
					} else {
						params = data;
					}
					return proxy(url, params, null, okTag, config, name);
				}

				function withNoParams(name, url, data, okTag, config) {
					return proxy(url, null, data, okTag, config, name);
				}

				function proxy(url, params, data, okTag, config, name) {
					
					$log.debug('remote ' + name + ': ' + url + ( data ? ', with data: ' + toJson(data) : ''));
					/**
					 * encrypt request data if useEncrypt and method=post
					 * add by ljw 
					 */
					if(useEncrypt && name === "post"){
						data = encryptDES(window.encryptKey,toJson(data));
						$log.debug('remote ' + name + ': ' + url + ( data ? ', with encrypt data: ' + data : ''));
					}
					config = extend(config || {}, {
						method : name,
						url : url,
						params : params,
						data : data,
						$scope : scope,
						ajaxPort : ajaxPort,
						$referer : refer
					});
					
					if (view)
						view.$$remoteTouch(submit);

					var failTag = errorTag, start = now(), http = $http(config), error;

					// clear error
					putData(failTag, null);

					http.then(function(response) {
						success(response.data, response.status, response.headers, config);
					}, function(response) {
						fail(response.data, response.status, response.headers, config);
					});

					function success(data, status, headers, config) {
						//success: status[200, 300)
						/**
						 * decrypt response data
						 * add by ljw 
						 */
						if(useEncrypt && name === "post"){
							data = decryptDES(window.encryptKey,data);
							var JSON_START = /^\s*(\[|\{[^\{])/, JSON_END = /[\}\]]\s*$/, PROTECTION_PREFIX = /^\)\]\}',?\n/;
							data = data.replace(PROTECTION_PREFIX, '');
							if (JSON_START.test(data) && JSON_END.test(data))
								data = fromJson(data, true);
						}
						error = getFailData && getFailData(data, status, headers, config);
						if (error) {
							$log.error('remote receive(' + (now() - start) + 'ms): ' + url + ', with error: ' + toJson(error));
							putData(failTag, error);
							scope.$root.$broadcast('$remoteError', url, error);
						} else {
							$log.debug('remote receive(' + (now() - start) + 'ms): ' + url + ( data ? ', with data: ' + toJson(data) : ''));
							if (okTag) {
								putData(okTag, data);
							} else {
								populate(scope, data);
							}
							scope.$root.$broadcast('$remoteSuccess', url, data);
						}
					}

					function fail(data, status, headers, config) {
						//error: other status
						error = getFailData && getFailData(data, status, headers, config);
						if (error) {
							$log.error('remote receive(' + (now() - start) + 'ms): ' + url + ', with error: ' + toJson(error));
							putData(failTag, error);
							scope.$root.$broadcast('$remoteError', url, error);
						}
					}

					var ret = {
						forward : function forward() {
							var args;
							if (arguments.length === 1) {
								if (!view)
									throw vError(47, 'no viewport, require target specified');
								args = [view, arguments[0]];
							} else {
								args = arguments;
							}
							http.then(function() {
								if (!error)
									_fastInvoke($targets, null, args);
							});
							return this;
						}
					};

					forEach(callbacks, function(fn, name) {
						ret[name] = function() {
							var args = _slice.call(arguments);
							http.then(function(response) {
								if (!error) {
									var arg = [response.data];
									arg = arg.concat(args);
									_fastInvoke(fn, scope, arg);
								}
							});
							return ret;
						};
					});

					return ret;

				}

				function putData(tag, data) {
					if (isFunction(tag))
						return tag(data);

					if (!isString(tag))
						throw vError(48, 'tag must be String or function(data)');

					var s = scope, name = tag;
					if (name.charAt(0) === '/') {
						name = name.substring(1);
						s = s.$root;
					} else {
						while (s && name.indexOf('../') === 0) {
							name = name.substring(3);
							s = s.$parent;
							if (!s)
								throw vError(49, 'invalid tag, wrong parent level, scope.$parent is null');
						}
					}
					if (name.indexOf('/') != -1)
						throw vError(50, 'invalid tag, require startWith "/" , "../" or none: {0}', tag);
					if (name) {
						s[name] = data;
					} else {
						populate(s, data);
					}
				}

				function populate(scope, data) {
					if (isObject(data) && !isArray(data)) {
						for (var key in data)
						if (data.hasOwnProperty(key)) {
							scope[key] = data[key];
						}
					} else {
						throw vError(51, "only object data {} could populate");
					}
				}

			};
		}

	}

	////////////////////////////////
	// $HttpProvider
	///////////////////////////////

	/**
	 * @vxdoc function
	 * @name vx.$http
	 * @requires $httpBackend
	 * @requires $browser
	 * @requires $cacheFactory
	 * @requires $rootScope
	 * @requires $q
	 * @requires $injector
	 *
	 * @description
	 * The `$http` service is a core VX service that facilitates communication with the remote
	 * HTTP servers via the browser's {@link https://developer.mozilla.org/en/xmlhttprequest
	 * XMLHttpRequest} object or via {@link http://en.wikipedia.org/wiki/JSONP JSONP}.
	 *
	 * For unit testing applications that use `$http` service, see
	 * {@link vMock.$httpBackend $httpBackend mock}.
	 *
	 * For a higher level of abstraction, please check out the {@link vResource.$resource
	 * $resource} service.
	 *
	 * The $http API is based on the {@link vx.$q deferred/promise APIs} exposed by
	 * the $q service. While for simple usage patterns this doesn't matter much, for advanced usage,
	 * it is important to familiarize yourself with these APIs and the guarantees they provide.
	 *
	 *
	 * # General usage
	 * The `$http` service is a function which takes a single argument — a configuration object —
	 * that is used to generate an HTTP request and returns  a {@link vx.$q promise}
	 * with two $http specific methods: `success` and `error`.
	 *
	 * <pre>
	 *   $http({method: 'GET', url: '/someUrl'}).
	 *     success(function(data, status, headers, config) {
	 *       // this callback will be called asynchronously
	 *       // when the response is available
	 *     }).
	 *     error(function(data, status, headers, config) {
	 *       // called asynchronously if an error occurs
	 *       // or server returns response with an error status.
	 *     });
	 * </pre>
	 *
	 * Since the returned value of calling the $http function is a `promise`, you can also use
	 * the `then` method to register callbacks, and these callbacks will receive a single argument –
	 * an object representing the response. See the API signature and type info below for more
	 * details.
	 *
	 * A response status code between 200 and 299 is considered a success status and
	 * will result in the success callback being called. Note that if the response is a redirect,
	 * XMLHttpRequest will transparently follow it, meaning that the error callback will not be
	 * called for such responses.
	 *
	 * # Shortcut methods
	 *
	 * Since all invocations of the $http service require passing in an HTTP method and URL, and
	 * POST/PUT requests require request data to be provided as well, shortcut methods
	 * were created:
	 *
	 * <pre>
	 *   $http.get('/someUrl').success(successCallback);
	 *   $http.post('/someUrl', data).success(successCallback);
	 * </pre>
	 *
	 * Complete list of shortcut methods:
	 *
	 * - {@link vx.$http#get $http.get}
	 * - {@link vx.$http#head $http.head}
	 * - {@link vx.$http#post $http.post}
	 * - {@link vx.$http#put $http.put}
	 * - {@link vx.$http#delete $http.delete}
	 * - {@link vx.$http#jsonp $http.jsonp}
	 *
	 *
	 * # Setting HTTP Headers
	 *
	 * The $http service will automatically add certain HTTP headers to all requests. These defaults
	 * can be fully configured by accessing the `$httpProvider.defaults.headers` configuration
	 * object, which currently contains this default configuration:
	 *
	 * - `$httpProvider.defaults.headers.common` (headers that are common for all requests):
	 *   - `Accept: application/json, text/plain, * / *`
	 * - `$httpProvider.defaults.headers.post`: (header defaults for POST requests)
	 *   - `Content-Type: application/json`
	 * - `$httpProvider.defaults.headers.put` (header defaults for PUT requests)
	 *   - `Content-Type: application/json`
	 *
	 * To add or overwrite these defaults, simply add or remove a property from these configuration
	 * objects. To add headers for an HTTP method other than POST or PUT, simply add a new object
	 * with the lowercased HTTP method name as the key, e.g.
	 * `$httpProvider.defaults.headers.get['My-Header']='value'`.
	 *
	 * Additionally, the defaults can be set at runtime via the `$http.defaults` object in the same
	 * fashion.
	 *
	 *
	 * # Transforming Requests and Responses
	 *
	 * Both requests and responses can be transformed using transform functions. By default, VX
	 * applies these transformations:
	 *
	 * Request transformations:
	 *
	 * - If the `data` property of the request configuration object contains an object, serialize it into
	 *   JSON format.
	 *
	 * Response transformations:
	 *
	 *  - If XSRF prefix is detected, strip it (see Security Considerations section below).
	 *  - If JSON response is detected, deserialize it using a JSON parser.
	 *
	 * To globally augment or override the default transforms, modify the `$httpProvider.defaults.transformRequest` and
	 * `$httpProvider.defaults.transformResponse` properties. These properties are by default an
	 * array of transform functions, which allows you to `push` or `unshift` a new transformation function into the
	 * transformation chain. You can also decide to completely override any default transformations by assigning your
	 * transformation functions to these properties directly without the array wrapper.
	 *
	 * Similarly, to locally override the request/response transforms, augment the `transformRequest` and/or
	 * `transformResponse` properties of the configuration object passed into `$http`.
	 *
	 *
	 * # Caching
	 *
	 * To enable caching, set the configuration property `cache` to `true`. When the cache is
	 * enabled, `$http` stores the response from the server in local cache. Next time the
	 * response is served from the cache without sending a request to the server.
	 *
	 * Note that even if the response is served from cache, delivery of the data is asynchronous in
	 * the same way that real requests are.
	 *
	 * If there are multiple GET requests for the same URL that should be cached using the same
	 * cache, but the cache is not populated yet, only one request to the server will be made and
	 * the remaining requests will be fulfilled using the response from the first request.
	 *
	 * A custom default cache built with $cacheFactory can be provided in $http.defaults.cache.
	 * To skip it, set configuration property `cache` to `false`.
	 *
	 * # Interceptors
	 *
	 * Before you start creating interceptors, be sure to understand the
	 * {@link vx.$q $q and deferred/promise APIs}.
	 *
	 * For purposes of global error handling, authentication, or any kind of synchronous or
	 * asynchronous pre-processing of request or postprocessing of responses, it is desirable to be
	 * able to intercept requests before they are handed to the server and
	 * responses before they are handed over to the application code that
	 * initiated these requests. The interceptors leverage the {@link vx.$q
	 * promise APIs} to fulfill this need for both synchronous and asynchronous pre-processing.
	 *
	 * The interceptors are service factories that are registered with the `$httpProvider` by
	 * adding them to the `$httpProvider.interceptors` array. The factory is called and
	 * injected with dependencies (if specified) and returns the interceptor.
	 *
	 * There are two kinds of interceptors (and two kinds of rejection interceptors):
	 *
	 *   * `request`: interceptors get called with http `config` object. The function is free to modify
	 *     the `config` or create a new one. The function needs to return the `config` directly or as a
	 *     promise.
	 *   * `requestError`: interceptor gets called when a previous interceptor threw an error or resolved
	 *      with a rejection.
	 *   * `response`: interceptors get called with http `response` object. The function is free to modify
	 *     the `response` or create a new one. The function needs to return the `response` directly or as a
	 *     promise.
	 *   * `responseError`: interceptor gets called when a previous interceptor threw an error or resolved
	 *      with a rejection.
	 *
	 *
	 * <pre>
	 *   // register the interceptor as a service
	 *   $provide.factory('myHttpInterceptor', function(dependency1, dependency2) {
	 *     return {
	 *       // optional method
	 *       'request': function(config, $q) {
	 *         // do something on success
	 *         return config || $q.when(config);
	 *       },
	 *
	 *       // optional method
	 *      'requestError': function(rejection, $q) {
	 *         // do something on error
	 *         if (canRecover(rejection)) {
	 *           return responseOrNewPromise
	 *         }
	 *         return $q.reject(rejection);
	 *       },
	 *
	 *
	 *
	 *       // optional method
	 *       'response': function(response, $q) {
	 *         // do something on success
	 *         return response || $q.when(response);
	 *       },
	 *
	 *       // optional method
	 *      'responseError': function(rejection, $q) {
	 *         // do something on error
	 *         if (canRecover(rejection)) {
	 *           return responseOrNewPromise
	 *         }
	 *         return $q.reject(rejection);
	 *       };
	 *     }
	 *   });
	 *
	 *   $httpProvider.interceptors.push('myHttpInterceptor');
	 *
	 *
	 *   // register the interceptor via an anonymous factory
	 *   $httpProvider.interceptors.push(function(dependency1, dependency2) {
	 *     return {
	 *      'request': function(config, $q) {
	 *          // same as above
	 *       },
	 *       'response': function(response, $q) {
	 *          // same as above
	 *       }
	 *   });
	 * </pre>
	 * # Security Considerations
	 *
	 * When designing web applications, consider security threats from:
	 *
	 * - {@link http://haacked.com/archive/2008/11/20/anatomy-of-a-subtle-json-vulnerability.aspx
	 *   JSON vulnerability}
	 * - {@link http://en.wikipedia.org/wiki/Cross-site_request_forgery XSRF}
	 *
	 * Both server and the client must cooperate in order to eliminate these threats. VX comes
	 * pre-configured with strategies that address these issues, but for this to work backend server
	 * cooperation is required.
	 *
	 * ## JSON Vulnerability Protection
	 *
	 * A {@link http://haacked.com/archive/2008/11/20/anatomy-of-a-subtle-json-vulnerability.aspx
	 * JSON vulnerability} allows third party website to turn your JSON resource URL into
	 * {@link http://en.wikipedia.org/wiki/JSONP JSONP} request under some conditions. To
	 * counter this your server can prefix all JSON requests with following string `")]}',\n"`.
	 * VX will automatically strip the prefix before processing it as JSON.
	 *
	 * For example if your server needs to return:
	 * <pre>
	 * ['one','two']
	 * </pre>
	 *
	 * which is vulnerable to attack, your server can return:
	 * <pre>
	 * )]}',
	 * ['one','two']
	 * </pre>
	 *
	 * VX will strip the prefix, before processing the JSON.
	 *
	 *
	 * ## Cross Site Request Forgery (XSRF) Protection
	 *
	 * {@link http://en.wikipedia.org/wiki/Cross-site_request_forgery XSRF} is a technique by which
	 * an unauthorized site can gain your user's private data. VX provides a mechanism
	 * to counter XSRF. When performing XHR requests, the $http service reads a token from a cookie
	 * (by default `XSRF-TOKEN`) and sets it as an HTTP header (`X-XSRF-TOKEN`). Since only JavaScript that
	 * runs on your domain could read the cookie, your server can be assured that the XHR came from
	 * JavaScript running on your domain. The header will not be set for cross-domain requests.
	 *
	 * To take advantage of this, your server needs to set a token in a JavaScript readable session
	 * cookie called `XSRF-TOKEN` on the first HTTP GET request. On subsequent XHR requests the
	 * server can verify that the cookie matches `X-XSRF-TOKEN` HTTP header, and therefore be sure
	 * that only JavaScript running on your domain could have sent the request. The token must be
	 * unique for each user and must be verifiable by the server (to prevent the JavaScript from making
	 * up its own tokens). We recommend that the token is a digest of your site's authentication
	 * cookie with a {@link https://en.wikipedia.org/wiki/Salt_(cryptography) salt} for added security.
	 *
	 * The name of the headers can be specified using the xsrfHeaderName and xsrfCookieName
	 * properties of either $httpProvider.defaults, or the per-request config object.
	 *
	 * @param {object} config Object describing the request to be made and how it should be
	 *    processed. The object has following properties:
	 *
	 *    - **method** – `{string}` – HTTP method (e.g. 'GET', 'POST', etc)
	 *    - **url** – `{string}` – Absolute or relative URL of the resource that is being requested.
	 *    - **params** – `{Object.<string|Object>}` – Map of strings or objects which will be turned to
	 *      `?key1=value1&key2=value2` after the url. If the value is not a string, it will be JSONified.
	 *    - **data** – `{string|Object}` – Data to be sent as the request message data.
	 *    - **headers** – `{Object}` – Map of strings representing HTTP headers to send to the server.
	 *    - **xsrfHeaderName** – `{string}` – Name of HTTP header to populate with the XSRF token.
	 *    - **xsrfCookieName** – `{string}` – Name of cookie containing the XSRF token.
	 *    - **transformRequest** – `{function(data, headersGetter)|Array.<function(data, headersGetter)>}` –
	 *      transform function or an array of such functions. The transform function takes the http
	 *      request body and headers and returns its transformed (typically serialized) version.
	 *    - **transformResponse** – `{function(data, headersGetter)|Array.<function(data, headersGetter)>}` –
	 *      transform function or an array of such functions. The transform function takes the http
	 *      response body and headers and returns its transformed (typically deserialized) version.
	 *    - **cache** – `{boolean|Cache}` – If true, a default $http cache will be used to cache the
	 *      GET request, otherwise if a cache instance built with
	 *      {@link vx.$cacheFactory $cacheFactory}, this cache will be used for
	 *      caching.
	 *    - **timeout** – `{number|Promise}` – timeout in milliseconds.
	 *    - **withCredentials** - `{boolean}` - whether to to set the `withCredentials` flag on the
	 *      XHR object. See {@link https://developer.mozilla.org/en/http_access_control#section_5
	 *      requests with credentials} for more information.
	 *    - **responseType** - `{string}` - see {@link
	 *      https://developer.mozilla.org/en-US/docs/DOM/XMLHttpRequest#responseType requestType}.
	 *
	 * @returns {HttpPromise} Returns a {@link vx.$q promise} object with the
	 *   standard `then` method and two http specific methods: `success` and `error`. The `then`
	 *   method takes two arguments a success and an error callback which will be called with a
	 *   response object. The `success` and `error` methods take a single argument - a function that
	 *   will be called when the request succeeds or fails respectively. The arguments passed into
	 *   these functions are destructured representation of the response object passed into the
	 *   `then` method. The response object has these properties:
	 *
	 *   - **data** – `{string|Object}` – The response body transformed with the transform functions.
	 *   - **status** – `{number}` – HTTP status code of the response.
	 *   - **headers** – `{function([headerName])}` – Header getter function.
	 *   - **config** – `{Object}` – The configuration object that was used to generate the request.
	 *
	 * @property {Array.<Object>} pendingRequests Array of config objects for currently pending
	 *   requests. This is primarily meant to be used for debugging purposes.
	 *
	 *
	 * @example
	 <example>
	 <file name="index.html">
	 <div v-controller="FetchCtrl">
	 <select v-model="method">
	 <option>GET</option>
	 <option>JSONP</option>
	 </select>
	 <input type="text" v-model="url" size="80"/>
	 <button v-click="fetch()">fetch</button><br>
	 <button v-click="updateModel('GET', 'http-hello.html')">Sample GET</button>
	 <button v-click="updateModel('JSONP', 'http://vxjs.org/greet.php?callback=JSON_CALLBACK&name=Super%20Hero')">Sample JSONP</button>
	 <button v-click="updateModel('JSONP', 'http://vxjs.org/doesntexist&callback=JSON_CALLBACK')">Invalid JSONP</button>
	 <pre>http status code: {{status}}</pre>
	 <pre>http response data: {{data}}</pre>
	 </div>
	 </file>
	 <file name="script.js">
	 function FetchCtrl($scope, $http, $templateCache) {
	 $scope.method = 'GET';
	 $scope.url = 'http-hello.html';

	 $scope.fetch = function() {
	 $scope.code = null;
	 $scope.response = null;

	 $http({method: $scope.method, url: $scope.url, cache: $templateCache}).
	 success(function(data, status) {
	 $scope.status = status;
	 $scope.data = data;
	 }).
	 error(function(data, status) {
	 $scope.data = data || "Request failed";
	 $scope.status = status;
	 });
	 };

	 $scope.updateModel = function(method, url) {
	 $scope.method = method;
	 $scope.url = url;
	 };
	 }
	 </file>
	 <file name="http-hello.html">
	 Hello, $http!
	 </file>
	 <file name="scenario.js">
	 it('should make an xhr GET request', function() {
	 element(':button:contains("Sample GET")').click();
	 element(':button:contains("fetch")').click();
	 expect(binding('status')).toBe('200');
	 expect(binding('data')).toMatch(/Hello, \$http!/);
	 });

	 it('should make a JSONP request to vxjs.org', function() {
	 element(':button:contains("Sample JSONP")').click();
	 element(':button:contains("fetch")').click();
	 expect(binding('status')).toBe('200');
	 expect(binding('data')).toMatch(/Super Hero!/);
	 });

	 it('should make JSONP request to invalid URL and invoke the error handler',
	 function() {
	 element(':button:contains("Invalid JSONP")').click();
	 element(':button:contains("fetch")').click();
	 expect(binding('status')).toBe('0');
	 expect(binding('data')).toBe('Request failed');
	 });
	 </file>
	 </example>
	 */
	function $HttpProvider() {
		var JSON_START = /^\s*(\[|\{[^\{])/, JSON_END = /[\}\]]\s*$/, PROTECTION_PREFIX = /^\)\]\}',?\n/, //
		CONTENT_TYPE_APPLICATION_JSON = {
			'Content-Type' : 'application/json.json;charset=utf-8'
		};

		var defaults = this.defaults = {
			// transform incoming response data
			transformResponse : [
			function(data) {
				if (isString(data)) {
					data = data.replace(PROTECTION_PREFIX, '');
					if (JSON_START.test(data) && JSON_END.test(data))
						data = fromJson(data, true);
				}
				return data;
			}],

			// transform outgoing request data
			transformRequest : [
			function(d) {
				return jsonRequest && isObject(d) && !isFile(d) ? toJson(d) : d;
			}],

			// default headers
			headers : {
				common : {
					'Accept' : 'application/json.json, text/plain, */*'
				},
				post : CONTENT_TYPE_APPLICATION_JSON,
				put : CONTENT_TYPE_APPLICATION_JSON,
				patch : CONTENT_TYPE_APPLICATION_JSON
			},

			xsrfCookieName : 'XSRF-TOKEN',
			xsrfHeaderName : 'X-XSRF-TOKEN'
		};

		// responseInterceptors already removed
		//var providerResponseInterceptors = this.responseInterceptors = [];
		/**
		 * Are order by request. I.E. they are applied in the same order as
		 * array on request, but revers order on response.
		 */
		var interceptorFactories = this.interceptors = [];

		var cacheDisabled = true, jsonRequest = true, defaultFn;
		this.useCache = function(cache) {
			cacheDisabled = !cache;
		};

		/* for old application, prefer using $.param as request, rather than use json.json*/
		this.useJsonRequest = function(json) {
			jsonRequest = !!json;
		};

		this.setDefaultCallback = function(fn) {
			defaultFn = fn;
		};

		this.$get = ['$httpBackend', '$browser', '$cacheFactory', '$rootScope', '$q', '$injector', httpFactory];

		function httpFactory($httpBackend, $browser, $cacheFactory, $rootScope, $$q, $injector) {
			var defaultCache = $cacheFactory('$http');
			/**
			 * Interceptors stored in reverse order. Inner interceptors before outer interceptors.
			 * The reversal is needed so that we can build up the interception chain around the
			 * server request.
			 */
			var reversedInterceptors = [];

			forEach(interceptorFactories, function(interceptorFactory) {
				reversedInterceptors.unshift(isString(interceptorFactory) ? $injector.get(interceptorFactory) : $injector.invoke(interceptorFactory));
			});

			function $http(requestConfig) {
				/*
				 config: {
				 method:
				 headers:
				 url:
				 data:
				 transformRequest:
				 transformResponse:
				 cache:
				 }
				 */
				var config = {
					transformRequest : defaults.transformRequest,
					transformResponse : defaults.transformResponse
				};
				var headers = {};

				extend(config, requestConfig);
				config.headers = headers;
				config.method = uppercase(config.method);

				extend(headers, defaults.headers.common, defaults.headers[lowercase(config.method)], requestConfig.headers);

				var xsrfValue = isSameDomain(config.url, $browser.url()) ? $browser.cookies()[config.xsrfCookieName || defaults.xsrfCookieName] : undefined;
				if (xsrfValue) {
					headers[(config.xsrfHeaderName || defaults.xsrfHeaderName)] = xsrfValue;
				}

				headers.$Referer = config.$referer || '/';
				var scope = config.$scope || $rootScope, $q = $$q.$new(scope);
				var serverRequest = function(config) {
					var reqData = transformData(config.data, headersGetter(headers), config.transformRequest);
					
					// strip content-type if data is undefined
					if (isUndefined(config.data) || !jsonRequest) {
						delete headers['Content-Type'];
					}

					if (isUndefined(config.withCredentials) && !isUndefined(defaults.withCredentials)) {
						config.withCredentials = defaults.withCredentials;
					}

					// send request
					return sendReq(config, reqData, headers, $q).then(transformResponse, transformResponse);
				};

				var chain = [serverRequest, undefined];

				// apply interceptors
				forEach(reversedInterceptors, function(interceptor) {
					if (interceptor.request || interceptor.requestError) {
						chain.unshift(interceptor.request, interceptor.requestError);
					}
					if (interceptor.response || interceptor.responseError) {
						chain.push(interceptor.response, interceptor.responseError);
					}
				});

				var needApply = true, promise;
				if (serverRequest !== chain[0])
					promise = $q.when(config);
				else {
					needApply = false;
					promise = serverRequest(config);
					chain.shift();
					chain.shift();
				}

				while (chain.length) {
					var thenFn = chain.shift();
					var rejectFn = chain.shift();
					promise = promise.then(thenFn, rejectFn);
				}

				var processed;

				promise.success = function(fn) {
					promise.then(function(response) {
						if (!processed)
							fn(response.data, response.status, response.headers, config);
					});
					return promise;
				};

				promise.error = function(fn) {
					promise.then(null, function(response) {
						if (!processed)
							fn(response.data, response.status, response.headers, config);
					});
					return promise;
				};

				if (defaultFn) {
					promise.then(function(response) {
						processed = defaultFn(response.data, response.status, response.headers, config);
					}, function(response) {
						processed = defaultFn(response.data, response.status, response.headers, config);
					});
				}

				if (needApply && !scope.$$phase && (!(scope.$$applied || scope.$root).$$phase))
					scope.$apply(null, '$httpRequestInterceptors->' + config.url);

				return promise;

				function transformResponse(response) {
					// make a copy since the response must be cacheable
					var resp = extend({}, response, {
						data : transformData(response.data, response.headers, config.transformResponse)
					});
					return (isSuccess(response.status)) ? resp : $q.reject(resp);
				}

			}


			$http.pendingRequests = [];

			/**
			 * @vxdoc method
			 * @name vx.$http#get
			 * @methodOf vx.$http
			 *
			 * @description
			 * Shortcut method to perform `GET` request
			 *
			 * @param {string} url Relative or absolute URL specifying the destination of the request
			 * @param {Object=} config Optional configuration object
			 * @returns {HttpPromise} Future object
			 */

			/**
			 * @vxdoc method
			 * @name vx.$http#delete
			 * @methodOf vx.$http
			 *
			 * @description
			 * Shortcut method to perform `DELETE` request
			 *
			 * @param {string} url Relative or absolute URL specifying the destination of the request
			 * @param {Object=} config Optional configuration object
			 * @returns {HttpPromise} Future object
			 */

			/**
			 * @vxdoc method
			 * @name vx.$http#head
			 * @methodOf vx.$http
			 *
			 * @description
			 * Shortcut method to perform `HEAD` request
			 *
			 * @param {string} url Relative or absolute URL specifying the destination of the request
			 * @param {Object=} config Optional configuration object
			 * @returns {HttpPromise} Future object
			 */

			/**
			 * @vxdoc method
			 * @name vx.$http#jsonp
			 * @methodOf vx.$http
			 *
			 * @description
			 * Shortcut method to perform `JSONP` request
			 *
			 * @param {string} url Relative or absolute URL specifying the destination of the request.
			 *                     Should contain `JSON_CALLBACK` string.
			 * @param {Object=} config Optional configuration object
			 * @returns {HttpPromise} Future object
			 */
			createShortMethods('get', 'delete', 'head', 'jsonp');

			/**
			 * @vxdoc method
			 * @name vx.$http#post
			 * @methodOf vx.$http
			 *
			 * @description
			 * Shortcut method to perform `POST` request
			 *
			 * @param {string} url Relative or absolute URL specifying the destination of the request
			 * @param {*} data Request content
			 * @param {Object=} config Optional configuration object
			 * @returns {HttpPromise} Future object
			 */

			/**
			 * @vxdoc method
			 * @name vx.$http#put
			 * @methodOf vx.$http
			 *
			 * @description
			 * Shortcut method to perform `PUT` request
			 *
			 * @param {string} url Relative or absolute URL specifying the destination of the request
			 * @param {*} data Request content
			 * @param {Object=} config Optional configuration object
			 * @returns {HttpPromise} Future object
			 */
			createShortMethodsWithData('post', 'put');

			/**
			 * @vxdoc property
			 * @name vx.$http#defaults
			 * @propertyOf vx.$http
			 *
			 * @description
			 * Runtime equivalent of the `$httpProvider.defaults` property. Allows configuration of
			 * default headers, withCredentials as well as request and response transformations.
			 *
			 * See "Setting HTTP Headers" and "Transforming Requests and Responses" sections above.
			 */
			$http.defaults = defaults;

			return $http;

			// -------------------------------------------------

			function createShortMethods(names) {
				forEach(arguments, function(name) {
					$http[name] = function(url, config) {
						return $http(extend(config || {}, {
							method : name,
							url : url
						}));
					};
				});
			}

			function createShortMethodsWithData(name) {
				forEach(arguments, function(name) {
					$http[name] = function(url, data, config) {
						return $http(extend(config || {}, {
							method : name,
							url : url,
							data : data
						}));
					};
				});
			}

			/**
			 * Makes the request
			 *
			 * !!! ACCESSES CLOSURE VARS:
			 * $httpBackend, defaults, $log, $rootScope, defaultCache, $http.pendingRequests
			 */
			function sendReq(config, reqData, reqHeaders, $q) {
				var deferred = $q.defer(), promise = deferred.promise, cache, cachedResp, url = buildUrl(config.url, config.params);

				$http.pendingRequests.push(config);
				promise.then(removePendingReq, removePendingReq);

				if ((config.cache || defaults.cache) && config.cache !== false && config.method == 'GET') {
					cache = isObject(config.cache) ? config.cache : isObject(defaults.cache) ? defaults.cache : defaultCache;
				}

				if (cache) {
					cachedResp = cache.get(url);
					if (cachedResp) {
						if (cachedResp.then) {
							// cached request has already been sent, but there is no response yet
							cachedResp.then(removePendingReq, removePendingReq);
							return cachedResp;
						} else {
							// serving from cache
							if (isArray(cachedResp)) {
								resolvePromise(cachedResp[1], cachedResp[0], copy(cachedResp[2]));
							} else {
								resolvePromise(cachedResp, 200, {});
							}
						}
					} else if (!cacheDisabled) {
						// put the promise for the non-transformed response into cache as a placeholder
						cache.put(url, promise);
					}
				}

				// if we won't have the response in cache, send the request to the backend
				if (!cachedResp) {
					var ajaxPort = config.ajaxPort || config.$scope && config.$scope.$$ajaxPort;
					$httpBackend(config.method, url, reqData, done, reqHeaders, config.timeout, config.withCredentials, config.responseType, ajaxPort);
				}

				return promise;

				// --------------------------------------------------------
				/**
				 * Callback registered to $httpBackend():
				 *  - caches the response if desired
				 *  - resolves the raw $http promise
				 *  - calls $apply
				 */
				function done(status, response, headersString) {
					if (!cacheDisabled && cache) {
						if (isSuccess(status)) {
							cache.put(url, [status, response, parseHeaders(headersString)]);
						} else {
							// remove promise from the cache
							cache.remove(url);
						}
					}
					var scope = config.$scope || $rootScope;
					resolvePromise(response, status, headersString);
					if (!scope.$$phase && (!(scope.$$applied || scope.$root).$$phase))
						scope.$apply(null, '$http->' + url);
				}

				/**
				 * Resolves the raw $http promise.
				 */
				function resolvePromise(response, status, headers) {
					// normalize internal statuses to 0
					status = Math.max(status, 0);
					//
					(isSuccess(status) ? deferred.resolve : deferred.reject)({
						data : response,
						status : status,
						headers : headersGetter(headers),
						config : config
					});
				}

				function removePendingReq() {
					var idx = indexOf($http.pendingRequests, config);
					if (idx !== -1)
						$http.pendingRequests.splice(idx, 1);
				}

				function buildUrl(url, params) {
					if (!params)
						return url;
					var parts = [];
					forEachSorted(params, function(value, key) {
						if (value === null || value === undefined)
							return;
						if (!isArray(value))
							value = [value];

						forEach(value, function(v) {
							if (isObject(v)) {
								v = toJson(v);
							}
							parts.push(encodeUriQuery(key) + '=' + encodeUriQuery(v));
						});
					});
					return url + ((url.indexOf('?') == -1) ? '?' : '&') + parts.join('&');
				}

			}

		}

		/**
		 * Parse headers into key value object
		 *
		 * @param {string} headers Raw headers as a string
		 * @returns {Object} Parsed headers as key value object
		 */
		function parseHeaders(headers) {
			var parsed = {}, key, val, i;
			if (!headers)
				return parsed;
			forEach(headers.split('\n'), function(line) {
				i = line.indexOf(':');
				key = lowercase(trim(line.substr(0, i)));
				val = trim(line.substr(i + 1));
				if (key) {
					if (parsed[key]) {
						parsed[key] += ', ' + val;
					} else {
						parsed[key] = val;
					}
				}
			});
			return parsed;
		}

		var IS_SAME_DOMAIN_URL_MATCH = /^(([^:]+):)?\/\/(\w+:{0,1}\w*@)?([\w\.\-]*)?(:([0-9]+))?(.*)$/;

		/**
		 * Parse a request and location URL and determine whether this is a same-domain request.
		 *
		 * @param {string} requestUrl The url of the request.
		 * @param {string} locationUrl The current browser location url.
		 * @returns {boolean} Whether the request is for the same domain.
		 */
		function isSameDomain(requestUrl, locationUrl) {
			var match = IS_SAME_DOMAIN_URL_MATCH.exec(requestUrl);
			// if requestUrl is relative, the regex does not match.
			if (match == null)
				return true;

			var domain1 = {
				protocol : match[2],
				host : match[4],
				port : int(match[6]) || DEFAULT_PORTS[match[2]] || null,
				// IE8 sets unmatched groups to '' instead of undefined.
				relativeProtocol : match[2] === undefined || match[2] === ''
			};

			match = URL_MATCH.exec(locationUrl);
			var domain2 = {
				protocol : match[1],
				host : match[3],
				port : int(match[5]) || DEFAULT_PORTS[match[1]] || null
			};

			return (domain1.protocol == domain2.protocol || domain1.relativeProtocol) && //
			domain1.host == domain2.host && //
			(domain1.port == domain2.port || (domain1.relativeProtocol && domain2.port == DEFAULT_PORTS[domain2.protocol]));
		}

		/**
		 * Returns a function that provides access to parsed headers.
		 *
		 * Headers are lazy parsed when first requested.
		 * @see parseHeaders
		 *
		 * @param {(string|Object)} headers Headers to provide access to.
		 * @returns {function(string=)} Returns a getter function which if called with:
		 *
		 *   - if called with single an argument returns a single header value or null
		 *   - if called with no arguments returns an object containing all headers.
		 */
		function headersGetter(headers) {
			var headersObj = isObject(headers) ? headers : undefined;
			var fn = function(name) {
				if (!headersObj)
					headersObj = parseHeaders(headers);
				if (name) {
					return headersObj[lowercase(name)] || null;
				}
				return headersObj;
			};
			fn.headers = headers;
			return fn;
		}

		/**
		 * Chain all given functions
		 *
		 * This function is used for both request and response transforming
		 *
		 * @param {*} data Data to transform.
		 * @param {function(string=)} headers Http headers getter fn.
		 * @param {(function|Array.<function>)} fns Function or an array of functions.
		 * @returns {*} Transformed data.
		 */
		function transformData(data, headers, fns) {
			if (isFunction(fns))
				return fns(data, headers);
			forEach(fns, function(fn) {
				data = fn(data, headers);
			});
			return data;
		}

		function isSuccess(status) {
			return 200 <= status && status < 300;
		}

	}

	////////////////////////////////
	// $QProvider
	///////////////////////////////

	/**
	 * @vxdoc service
	 * @name vx.$q
	 * @requires $rootScope
	 *
	 * @description
	 * A promise/deferred implementation inspired by [Kris Kowal's Q](https://github.com/kriskowal/q).
	 *
	 * [The CommonJS Promise proposal](http://wiki.commonjs.org/wiki/Promises) describes a promise as an
	 * interface for interacting with an object that represents the result of an action that is
	 * performed asynchronously, and may or may not be finished at any given point in time.
	 *
	 * From the perspective of dealing with error handling, deferred and promise APIs are to
	 * asynchronous programming what `try`, `catch` and `throw` keywords are to synchronous programming.
	 *
	 * <pre>
	 *   // for the purpose of this example let's assume that variables `$q` and `scope` are
	 *   // available in the current lexical scope (they could have been injected or passed in).
	 *
	 *   function asyncGreet(name) {
	 *     var deferred = $q.defer();
	 *
	 *     setTimeout(function() {
	 *       // since this fn executes async in a future turn of the event loop, we need to wrap
	 *       // our code into an $apply call so that the model changes are properly observed.
	 *       scope.$apply(function() {
	 *         if (okToGreet(name)) {
	 *           deferred.resolve('Hello, ' + name + '!');
	 *         } else {
	 *           deferred.reject('Greeting ' + name + ' is not allowed.');
	 *         }
	 *       });
	 *     }, 1000);
	 *
	 *     return deferred.promise;
	 *   }
	 *
	 *   var promise = asyncGreet('Robin Hood');
	 *   promise.then(function(greeting, $q) {
	 *     alert('Success: ' + greeting);
	 *   }, function(reason, $q) {
	 *     alert('Failed: ' + reason);
	 *   });
	 * </pre>
	 *
	 * At first it might not be obvious why this extra complexity is worth the trouble. The payoff
	 * comes in the way of
	 * [guarantees that promise and deferred APIs make](https://github.com/kriskowal/uncommonjs/blob/master/promises/specification.md).
	 *
	 * Additionally the promise api allows for composition that is very hard to do with the
	 * traditional callback ([CPS](http://en.wikipedia.org/wiki/Continuation-passing_style)) approach.
	 * For more on this please see the [Q documentation](https://github.com/kriskowal/q) especially the
	 * section on serial or parallel joining of promises.
	 *
	 *
	 * # The Deferred API
	 *
	 * A new instance of deferred is constructed by calling `$q.defer()`.
	 *
	 * The purpose of the deferred object is to expose the associated Promise instance as well as APIs
	 * that can be used for signaling the successful or unsuccessful completion of the task.
	 *
	 * **Methods**
	 *
	 * - `resolve(value)` – resolves the derived promise with the `value`. If the value is a rejection
	 *   constructed via `$q.reject`, the promise will be rejected instead.
	 * - `reject(reason)` – rejects the derived promise with the `reason`. This is equivalent to
	 *   resolving it with a rejection constructed via `$q.reject`.
	 *
	 * **Properties**
	 *
	 * - promise – `{Promise}` – promise object associated with this deferred.
	 *
	 *
	 * # The Promise API
	 *
	 * A new promise instance is created when a deferred instance is created and can be retrieved by
	 * calling `deferred.promise`.
	 *
	 * The purpose of the promise object is to allow for interested parties to get access to the result
	 * of the deferred task when it completes.
	 *
	 * **Methods**
	 *
	 * - `then(successCallback, errorCallback)` – regardless of when the promise was or will be resolved
	 *   or rejected calls one of the success or error callbacks asynchronously as soon as the result
	 *   is available. The callbacks are called with a single argument the result or rejection reason.
	 *
	 *   This method *returns a new promise* which is resolved or rejected via the return value of the
	 *   `successCallback` or `errorCallback`.
	 *
	 * - `always(callback)` – allows you to observe either the fulfillment or rejection of a promise,
	 *   but to do so without modifying the final value. This is useful to release resources or do some
	 *   clean-up that needs to be done whether the promise was rejected or resolved. See the [full
	 *   specification](https://github.com/kriskowal/q/wiki/API-Reference#promisefinallycallback) for
	 *   more information.
	 *
	 * # Chaining promises
	 *
	 * Because calling `then` api of a promise returns a new derived promise, it is easily possible
	 * to create a chain of promises:
	 *
	 * <pre>
	 *   promiseB = promiseA.then(function(result, $q) {
	 *     return result + 1;
	 *   });
	 *
	 *   // promiseB will be resolved immediately after promiseA is resolved and its value will be
	 *   // the result of promiseA incremented by 1
	 * </pre>
	 *
	 * It is possible to create chains of any length and since a promise can be resolved with another
	 * promise (which will defer its resolution further), it is possible to pause/defer resolution of
	 * the promises at any point in the chain. This makes it possible to implement powerful APIs like
	 * $http's response interceptors.
	 *
	 *
	 * # Differences between Kris Kowal's Q and $q
	 *
	 *  There are three main differences:
	 *
	 * - $q is integrated with the {@link vx.$rootScope.Scope} Scope model observation
	 *   mechanism in vx, which means faster propagation of resolution or rejection into your
	 *   models and avoiding unnecessary browser repaints, which would result in flickering UI.
	 * - $q promises are recognized by the templating engine in vx, which means that in templates
	 *   you can treat promises attached to a scope as if they were the resulting values.
	 * - Q has many more features than $q, but that comes at a cost of bytes. $q is tiny, but contains
	 *   all the important functionality needed for common async tasks.
	 *
	 *  # Testing
	 *
	 *  <pre>
	 *    it('should simulate promise', inject(function($q, $rootScope) {
	 *      var deferred = $q.defer();
	 *      var promise = deferred.promise;
	 *      var resolvedValue;
	 *
	 *      promise.then(function(value, $q) { resolvedValue = value; });
	 *      expect(resolvedValue).toBeUndefined();
	 *
	 *      // Simulate resolving of promise
	 *      deferred.resolve(123);
	 *      // Note that the 'then' function does not get called synchronously.
	 *      // This is because we want the promise API to always be async, whether or not
	 *      // it got called synchronously or asynchronously.
	 *      expect(resolvedValue).toBeUndefined();
	 *
	 *      // Propagate promise resolution to 'then' functions using $apply().
	 *      $rootScope.$apply();
	 *      expect(resolvedValue).toEqual(123);
	 *    });
	 *  </pre>
	 */
	function $QProvider() {

		/**
		 * Constructs a promise manager.
		 *
		 * @param {function(function)} nextTick Function for executing functions in the next turn.
		 * @param {function(...*)} exceptionHandler Function into which unexpected exceptions are passed for
		 *     debugging purposes.
		 * @returns {object} Promise manager.
		 */
		function qFactory(nextTick/*,                                                                                                                                                                                                                                                            exceptionHandler*/, log) {
			/**
			 * @vxdoc
			 * @name vx.$q#defer
			 * @methodOf vx.$q
			 * @description
			 * Creates a `Deferred` object which represents a task which will finish in the future.
			 *
			 * @returns {Deferred} Returns a new instance of deferred.
			 */
			var defer = function() {
				var pending = [], value, deferred;
				deferred = {
					resolve : function(val) {
						if (pending) {
							var callbacks = pending;
							pending = undefined;
							value = ref(val);
							if (callbacks.length) {
								nextTick(function() {
									var callback;
									for (var i = 0, ii = callbacks.length; i < ii; i++) {
										callback = callbacks[i];
										value.then(callback[0], callback[1]);
									}
								});
							}
						}
					},
					reject : function(reason) {
						deferred.resolve(reject(reason));
					},
					promise : {
						then : function(callback, errback) {
							var result = defer();
							var wrappedCallback = function(value) {
								//try {
								result.resolve((callback || defaultCallback)(value, $q));
								//} catch(e) {
								//  log.error(e);
								//	exceptionHandler(e);
								//	result.reject(e);
								//}
							};
							var wrappedErrback = function(reason) {
								//try {
								result.resolve((errback || defaultErrback)(reason, $q));
								//} catch(e) {
								//  log.error(e);
								//	exceptionHandler(e);
								//	result.reject(e);
								//}
							};
							if (pending) {
								pending.push([wrappedCallback, wrappedErrback]);
							} else {
								value.then(wrappedCallback, wrappedErrback);
							}
							return result.promise;
						},
						always : function(callback) {

							function makePromise(value, resolved) {
								var result = defer();
								if (resolved) {
									result.resolve(value);
								} else {
									result.reject(value);
								}
								return result.promise;
							}

							function handleCallback(value, isResolved) {
								var callbackOutput = null;
								try {
									callbackOutput = (callback || defaultCallback)();
								} catch(e) {
									return makePromise(e, false);
								}
								if (callbackOutput && callbackOutput.then) {
									return callbackOutput.then(function() {
										return makePromise(value, isResolved);
									}, function(error) {
										return makePromise(error, false);
									});
								} else {
									return makePromise(value, isResolved);
								}
							}

							return this.then(function(value) {
								return handleCallback(value, true);
							}, function(error) {
								return handleCallback(error, false);
							});
						}
					}
				};
				return deferred;
			};
			var ref = function(value) {
				if (value && value.then)
					return value;
				return {
					then : function(callback) {
						var result = defer();
						nextTick(function() {
							result.resolve(callback(value, $q));
						});
						return result.promise;
					}
				};
			};
			/**
			 * @vxdoc
			 * @name vx.$q#reject
			 * @methodOf vx.$q
			 * @description
			 * Creates a promise that is resolved as rejected with the specified `reason`. This api should be
			 * used to forward rejection in a chain of promises. If you are dealing with the last promise in
			 * a promise chain, you don't need to worry about it.
			 *
			 * When comparing deferreds/promises to the familiar behavior of try/catch/throw, think of
			 * `reject` as the `throw` keyword in JavaScript. This also means that if you "catch" an error via
			 * a promise error callback and you want to forward the error to the promise derived from the
			 * current promise, you have to "rethrow" the error by returning a rejection constructed via
			 * `reject`.
			 *
			 * <pre>
			 *   promiseB = promiseA.then(function(result, $q) {
			 *     // success: do something and resolve promiseB
			 *     //          with the old or a new result
			 *     return result;
			 *   }, function(reason, $q) {
			 *     // error: handle the error if possible and
			 *     //        resolve promiseB with newPromiseOrValue,
			 *     //        otherwise forward the rejection to promiseB
			 *     if (canHandle(reason)) {
			 *      // handle the error and recover
			 *      return newPromiseOrValue;
			 *     }
			 *     return $q.reject(reason);
			 *   });
			 * </pre>
			 *
			 * @param {*} reason Constant, message, exception or an object representing the rejection reason.
			 * @returns {Promise} Returns a promise that was already resolved as rejected with the `reason`.
			 */
			var reject = function(reason) {
				return {
					then : function(callback, errback) {
						var result = defer();
						nextTick(function() {
							result.resolve((errback || defaultErrback)(reason, $q));
						});
						return result.promise;
					}
				};
			};
			/**
			 * @vxdoc
			 * @name vx.$q#when
			 * @methodOf vx.$q
			 * @description
			 * Wraps an object that might be a value or a (3rd party) then-able promise into a $q promise.
			 * This is useful when you are dealing with an object that might or might not be a promise, or if
			 * the promise comes from a source that can't be trusted.
			 *
			 * @param {*} value Value or a promise
			 * @returns {Promise} Returns a promise of the passed value or promise
			 */
			var when = function(value, callback, errback) {
				var result = defer(), done;
				var wrappedCallback = function(value) {
					//try {
					return (callback || defaultCallback)(value, $q);
					//} catch (e) {
					//  log.error(e);
					//	exceptionHandler(e);
					//	return reject(e);
					//}
				};
				var wrappedErrback = function(reason) {
					//try {
					return (errback || defaultErrback)(reason, $q);
					//} catch (e) {
					//  log.error(e);
					//	exceptionHandler(e);
					//	return reject(e);
					//}
				};
				nextTick(function() {
					ref(value).then(function(value) {
						if (done)
							return;
						done = true;
						result.resolve(ref(value).then(wrappedCallback, wrappedErrback));
					}, function(reason) {
						if (done)
							return;
						done = true;
						result.resolve(wrappedErrback(reason));
					});
				});
				return result.promise;
			};

			function defaultCallback(value) {
				return value;
			}

			function defaultErrback(reason) {
				return reject(reason);
			}

			/**
			 * @vxdoc
			 * @name vx.$q#all
			 * @methodOf vx.$q
			 * @description
			 * Combines multiple promises into a single promise that is resolved when all of the input
			 * promises are resolved.
			 *
			 * @param {Array.<Promise>|Object.<Promise>} promises An array or hash of promises.
			 * @returns {Promise} Returns a single promise that will be resolved with an array/hash of values,
			 *   each value corresponding to the promise at the same index/key in the `promises` array/hash. If any of
			 *   the promises is resolved with a rejection, this resulting promise will be resolved with the
			 *   same rejection.
			 */
			function all(promises) {
				var deferred = defer(), counter = 0, results = isArray(promises) ? [] : {};
				forEach(promises, function(promise, key) {
					counter++;
					ref(promise).then(function(value) {
						if (results.hasOwnProperty(key))
							return;
						results[key] = value;
						if (!(--counter))
							deferred.resolve(results);
					}, function(reason) {
						if (results.hasOwnProperty(key))
							return;
						deferred.reject(reason);
					});
				});
				if (counter === 0) {
					deferred.resolve(results);
				}
				return deferred.promise;
			}

			var $q = {
				defer : defer,
				reject : reject,
				when : when,
				all : all
			};

			return $q;
		}


		this.$get = ['$rootScope', /*'$exceptionHandler',*/'$log',
		function($rootScope, /*$exceptionHandler,*/$log) {
			var $q = qFactory(function(callback) {
				$rootScope.$evalAsync(callback);
			}, /*$exceptionHandler,*/$log);

			$q.$new = function(scope) {
				if (scope === $rootScope)
					return $q;
				return qFactory(function(callback) {
					scope.$evalAsync(callback);
				}, /*$exceptionHandler,*/$log);
			};

			return $q;
		}];

	}

	////////////////////////////////
	// $HttpBackendProvider
	///////////////////////////////

	/**
	 * @vxdoc object
	 * @name vx.$httpBackend
	 * @requires $browser
	 * @requires $window
	 * @requires $document
	 *
	 * @description
	 * HTTP backend used by the {@link vx.$http service} that delegates to
	 * XMLHttpRequest object or JSONP and deals with browser incompatibilities.
	 *
	 * You should never need to use this service directly, instead use the higher-level abstractions:
	 * {@link vx.$http $http} or {@link vResource.$resource $resource}.
	 *
	 * During testing this implementation is swapped with {@link vMock.$httpBackend mock
	 * $httpBackend} which can be trained with responses.
	 */

	function $HttpBackendProvider() {
		var ajaxTransport, antiCache = 0/* 0-disable, 1-every load time, 2-every request time */;
		var setting = {
			ajaxQueue : null,
			ajaxTimeout : 30000/* 30 seconds */,
			ajaxQueueSize : 5,
			ajaxAborted : false, // false-no, true-yes
			beforeSend : noop,
			afterReceived : noop,
			$requestCount : 0
		}, ports = {};

		this.useExternalAjax = function(yes) {
			if (!!yes)
				ajaxTransport = jqLite.ajax;
		};

		//0-disable, 1-every load time, 2-every request time
		this.useAntiCache = function(anti) {
			antiCache = anti;
		};

		//---- START of default setting config
		this.indicator = function(pre, post) {
			setting.beforeSend = pre;
			setting.afterReceived = post;
		};

		this.useAjaxQueue = function(queue, aborted) {
			setting.ajaxQueueSize = isNumber(queue) ? queue : !!queue ? 5 : 0;
			setting.ajaxAborted = !!aborted;
		};

		this.setTimeout = function(timeout) {
			setting.ajaxTimeout = timeout;
		};
		//---- END of default setting config

		/**
		 * could setting:
		 *   ajaxTimeout : 30000, // in milliseconds
		 *   ajaxQueueSize : 5,
		 *   ajaxAborted : false, // false-no, true-yes
		 *   beforeSend : noop,
		 *   afterReceived : noop,
		 */
		this.config = function(port, obj) {
			if (arguments.length === 1) {
				obj = port;
				extend(setting, obj);
			} else {
				ports[port] = obj;
			}
		};

		function ajaxQueueFactory(log, config) {
			return {
				reqs : [],
				// current status
				xhr : false,
				requesting : false,
				// function
				next : function() {
					if (this.reqs.length === 0 || this.requesting)
						return;
					var req = this.reqs.shift(), complete = req.complete, self = this;
					req.complete = function() {
						if (complete)
							complete.apply(this, arguments);
						self.requesting = false, self.xhr = false;
						self.next();
					};
					this.requesting = req, this.xhr = ajaxTransport(req);
				},
				add : function(req) {
					if (config.ajaxQueueSize === 0) {
						ajaxTransport(req);
						return;
					}

					//abort same url
					if (this.requesting && requestEqual(this.requesting, req)) {
						if (this.xhr.readyState !== 4) {
							log.warn("httpBackend duplicate sending: " + req.url);
							if (config.ajaxAborted) {
								this.xhr.abort();
								this.requesting = false, this.xhr = false;
							} else {
								return requestAppend(this.requesting, req);
							}
						}
					}

					// max queue size, remove first one
					if (this.reqs.length === config.ajaxQueueSize) {
						var p = this.reqs.shift();
						log.warn("httpBackend queue overflow, add: " + req.url + ", remove: " + p.url);
					}

					this.reqs.push(req);
					this.next();
				}
			};

			function requestEqual(req, req1) {
				return req.url === req1.url && req.type === req1.type && equals(req.data, req1.data);
			}

			function requestAppend(req, req1) {
				var reqSuccess = req.success, reqError = req.error;
				req.success = function(data, status, xhr) {
					reqSuccess(data, status, xhr);
					req1.success(data, status, xhr);
				};
				req.error = function(xhr, status, error) {
					reqError(xhr, status, error);
					req1.error(xhr, status, error);
				};
			}

		}


		this.$get = ['$browser', '$window', '$document', '$log',
		function($browser, $window, $document, $log) {
			return createHttpBackend($browser, $window.vx.callbacks, $window.location.protocol.replace(':', ''), $log);
		}];

		//@formatter:off
		var XHR = window.XMLHttpRequest || function() {
			try { return new window.ActiveXObject("Microsoft.XMLHTTP"); } catch (e0) {}
			try { return new window.ActiveXObject("Msxml2.XMLHTTP.6.0"); } catch (e1) {}
			try { return new window.ActiveXObject("Msxml2.XMLHTTP.3.0"); } catch (e2) {}
			try { return new window.ActiveXObject("Msxml2.XMLHTTP"); } catch (e3) {	}
			throw vError(52, "This browser does not support XMLHttpRequest.");
		};
		//@formatter:on

		function createHttpBackend($browser, callbacks, locationProtocol, log) {
			if (!ajaxTransport)
				ajaxTransport = ajaxReq;

			return httpBackend;

			// TODO(vojta): fix the signature
			// for script signature is httpBackend(node, url, type, callback, ajaxPort)
			function httpBackend(method, url, post, callback, headers, timeout, withCredentials, responseType, ajaxPort) {

				// for load script
				var scripted = false;
				if (arguments.length < 9) {
					ajaxPort = arguments[4];
					scripted = true;
				}
				
				// initiate ajaxQueue for ajaxPort config
				var config = setting;
				if (isDefined(ajaxPort)) {
					config = ports[ajaxPort];
					if (!config || !config.ajaxQueue) {
						config = ports[ajaxPort] = extend({}, setting, config || {});
						config.$requestCount = 0;
						config.ajaxQueue = ajaxQueueFactory(log, config);
					}
				} else if (!config.ajaxQueue) {
					config.ajaxQueue = ajaxQueueFactory(log, config);
				}

				if (config.$requestCount === 0)
					config.beforeSend();
				config.$requestCount++;

				url = url || $browser.url();
				// Add anti-cache in url if needed
				if (scripted || method === 'GET') {
					url = antiCacheURL(url);
				}

				$browser.$$incOutstandingRequestCount();
				
				if (scripted) {
					var node = method, type = post;
					scriptReq(url, function(status) {
						if (!status) {
							completeRequest(callback, 200, true);
						} else {
							completeRequest(callback, status);
						}
					}, node, type, timeout || config.ajaxTimeout);
				} else if (method == 'JSONP') {
					/*
					* Sample:
					* request : http://xxx.com/xxx.do?callback=JSON_CALLBACK&...
					*   *JSON_CALLBACK will replace with callbackId (_xxx)
					* server-side should return
					* vx.callbacks._xxx (object);  // object is any js object
					*/
					//***  jQuery jsonp cannot deal with error
					var callbackId = '_' + (callbacks.counter++).toString(36);
					callbacks[callbackId] = function(data) {
						callbacks[callbackId].data = data;
					};
					scriptReq(url.replace('JSON_CALLBACK', 'vx.callbacks.' + callbackId), function(status) {
						if (callbacks[callbackId].data) {
							completeRequest(callback, 200, callbacks[callbackId].data);
						} else {
							completeRequest(callback, status);
						}
						delete callbacks[callbackId];
					}, null, null, timeout || config.ajaxTimeout);
				} else {
					var ajaxSetting = {
						url : url,
						type : method,
						dataType : 'text',
						data : post,
						headers : headers,
						async : true,
						timeout : timeout || config.ajaxTimeout,
						converters : {//*** only for jQuery
							"text json" : true //disable jQuery json.json parse
						},
						// responseText is the old-school way of retrieving response (supported by IE8 & 9)
						// response and responseType properties were introduced in XHR Level2 spec (supported by IE10)
						success : function(data, status, xhr) {
							completeRequest(callback, xhr.status, (xhr.responseType ? xhr.response : xhr.responseText) || data/* jsonp */, getAllResponseHeaders(xhr));
						},
						error : function(xhr, status, error) {
							completeRequest(callback, status || xhr.status, xhr.statusText, getAllResponseHeaders(xhr));
						}
					};
					ajaxSetting.xhrFields = {};
					//*** only for jQuery
					if (withCredentials) {
						ajaxSetting.xhrFields.withCredentials = true;
					}
					if (responseType) {
						ajaxSetting.xhrFields.responseType = responseType;
					}

					var ajaxQ = config.ajaxQueue;
					ajaxQ.add(ajaxSetting);

				}

				function getAllResponseHeaders(xhr) {
					var responseHeaders;
					try {
						responseHeaders = xhr.getAllResponseHeaders();
					} catch(e) {
					}

					// TODO(vojta): remove once Firefox 21 gets released.
					// begin: workaround to overcome Firefox CORS http response headers bug
					// https://bugzilla.mozilla.org/show_bug.cgi?id=608735
					// Firefox already patched in nightly. Should land in Firefox 21.

					// CORS "simple response headers" http://www.w3.org/TR/cors/
					var value, simpleHeaders = ["Cache-Control", "Content-Language", "Content-Type", "Expires", "Last-Modified", "Pragma"];
					if (!responseHeaders) {
						responseHeaders = "";
						forEach(simpleHeaders, function(header) {
							var value = xhr.getResponseHeader(header);
							if (value) {
								responseHeaders += header + ": " + value + "\n";
							}
						});
					}
					// end of the workaround.
					return responseHeaders;
				}

				function completeRequest(callback, status, response, headersString) {
					var protocol = (url.match(URL_MATCH) || ['', locationProtocol])[1];

					// fix status code for file protocol (it's always 0)
					status = (protocol == 'file') ? ( response ? 200 : 404) : status;

					// for webkit, special in android
					if (status === 0 && response) {
						log.warn('ajax strange status: 0');
						status = 200;
					}

					// normalize IE bug (http://bugs.jquery.com/ticket/1450)
					status = status === 1223 ? 204 : status;

					callback(status, response, headersString);
					$browser.$$completeOutstandingRequest(noop);

					config.$requestCount--;
					if (config.$requestCount === 0)
						config.afterReceived();

				}

			}

			function antiCacheURL(url) {
				if (!antiCache)
					return url;
				return uniqueURL(url, antiCache === 1 ? vx.$TIMESTAMP : now());
				function uniqueURL(url, ts) {
					// used for antiCache
					var mm = url.split('#');
					var rts = /([?&])_=[^&]*/, rquery = /\?/;
					// try replacing _= if it is there
					var ret = mm[0].replace(rts, "$1_=" + ts);
					// if nothing was replaced, add timestamp to the end
					return ret + ((ret === mm[0] ) ? (rquery.test(mm[0]) ? "&" : "?" ) + "_=" + ts : "" ) + (mm[1] ? '#' + mm[1] : '');
				}

			}

			function scriptReq(url, done, el, type, timeout) {
				// we can't use jQuery/jqLite here because jQuery does crazy shit with script elements, e.g.:
				// - fetches local scripts via XHR and evals them
				// - adds and immediately removes script elements from the document
				var script = document.createElement('script'), doneWrapper = function(status) {
					if (msie < 9)
						script.onreadystatechange = noop;
					else
						script.onload = script.onerror = noop;
					if (deferId) {
						$browser.defer.cancel(deferId);
						deferId = null;
					}
					if (!el)
						document.body.removeChild(script);
					if (done)
						done(status);
				}, deferId, status = 0;
				script.type = type || 'text/javascript';
				script.src = url;
				if (msie < 9) {
					script.onreadystatechange = function() {
						if (/loaded|complete/.test(script.readyState)) {
							doneWrapper(status);
						}
					};
				} else {
					script.onload = function() {
						doneWrapper(status);
					};
					script.onerror = function() {
						status = -2;
						doneWrapper(status);
					};
				}
				(el || document.body).appendChild(script);
				
				if (timeout > 0) {
					deferId = $browser.defer(function() {
						status = -1;
						doneWrapper(status);
					}, timeout);
				}				
				//return doneWrapper;
			}

			function ajaxReq(ajaxSetting) {
				var xhr = new XHR();
				xhr.open(ajaxSetting.type, ajaxSetting.url, ajaxSetting.async);
				forEach(ajaxSetting.headers, function(value, key) {
					if (value)
						xhr.setRequestHeader(key, value);
				});

				var status, deferId;
				// In IE6 and 7, this might be called synchronously when xhr.send below is called and the
				// response is in the cache. the promise api will ensure that to the app code the api is
				// always async
				xhr.onreadystatechange = function() {
					if (status || xhr.readyState == 4) {
						xhr.onreadystatechange = noop;
						if (deferId) {
							$browser.defer.cancel(deferId);
							deferId = null;
						}
						if (!status && ((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304)) {
							if (ajaxSetting.complete)
								ajaxSetting.complete(xhr, 'success');
							ajaxSetting.success(xhr.response || xhr.responseText, xhr.status, xhr);
						} else {
							if (ajaxSetting.complete)
								ajaxSetting.complete(xhr, 'error');
							ajaxSetting.error(xhr, status || xhr.status, 'error');
						}
					}
				};

				if (ajaxSetting.xhrFields.withCredentials) {
					xhr.withCredentials = true;
				}
				if (ajaxSetting.xhrFields.responseType) {
					xhr.responseType = ajaxSetting.xhrFields.responseType;
				}

				if (ajaxSetting.beforeSend && ajaxSetting.beforeSend.call(ajaxSetting.context, xhr, ajaxSetting) === false) {
					status = -2;
					xhr.abort();
					xhr.onreadystatechange();
					return false;
				}

				xhr.send(ajaxSetting.data || '');

				if (ajaxSetting.timeout > 0) {
					deferId = $browser.defer(function() {
						status = -1;
						xhr.abort();
						xhr.onreadystatechange();
					}, ajaxSetting.timeout);
				}

				return xhr;
			}

		}

	}

	////////////////////////////////
	// $TimeoutProvider
	///////////////////////////////
	function $TimeoutProvider() {
		this.$get = ['$rootScope', '$browser', '$q', /*'$exceptionHandler',*/'$log',
		function($rootScope, $browser, $$q, /*$exceptionHandler,*/$log) {
			var deferreds = {};

			/**
			 * @vxdoc function
			 * @name vx.$timeout
			 * @requires $browser
			 *
			 * @description
			 * VX's wrapper for `window.setTimeout`. The `fn` function is wrapped into a try/catch
			 * block and delegates any exceptions to
			 * {@link vx.$exceptionHandler $exceptionHandler} service.
			 *
			 * The return value of registering a timeout function is a promise, which will be resolved when
			 * the timeout is reached and the timeout function is executed.
			 *
			 * To cancel a timeout request, call `$timeout.cancel(promise)`.
			 *
			 * In tests you can use {@link vMock.$timeout `$timeout.flush()`} to
			 * synchronously flush the queue of deferred functions.
			 *
			 * @param {function()} fn A function, whose execution should be delayed.
			 * @param {number=} [delay=0] Delay in milliseconds.
			 * @param {boolean=} [invokeApply=true] If set to `false` skips model dirty checking, otherwise
			 *   will invoke `fn` within the {@link vx.$rootScope.Scope#$apply $apply} block.
			 * @returns {Promise} Promise that will be resolved when the timeout is reached. The value this
			 *   promise will be resolved with is the return value of the `fn` function.
			 */
			function timeout(fn, delay, invokeApply) {
				var scope = $rootScope, $q = $$q;
				if (isScope(invokeApply)) {
					scope = invokeApply;
					$q = $$q.$new(scope);
				}
				var deferred = $q.defer(), promise = deferred.promise, skipApply = (isDefined(invokeApply) && !invokeApply), timeoutId, cleanup;
				timeoutId = $browser.defer(function() {
					try {
						deferred.resolve(fn());
					} catch(e) {
						deferred.reject(e);
						$log.error(formatError(e));
						//$exceptionHandler(e);
					}

					if (!skipApply)
						scope.$apply(null, '$timeout');
				}, delay);
				cleanup = function() {
					delete deferreds[promise.$$timeoutId];
				};

				promise.$$timeoutId = timeoutId;
				deferreds[timeoutId] = deferred;
				promise.then(cleanup, cleanup);

				return promise;
			}

			/**
			 * @vxdoc function
			 * @name vx.$timeout#cancel
			 * @methodOf vx.$timeout
			 *
			 * @description
			 * Cancels a task associated with the `promise`. As a result of this, the promise will be
			 * resolved with a rejection.
			 *
			 * @param {Promise=} promise Promise returned by the `$timeout` function.
			 * @returns {boolean} Returns `true` if the task hasn't executed yet and was successfully
			 *   canceled.
			 */
			timeout.cancel = function(promise) {
				if (promise && promise.$$timeoutId in deferreds) {
					deferreds[promise.$$timeoutId].reject('canceled');
					return $browser.defer.cancel(promise.$$timeoutId);
				}
				return false;
			};

			return timeout;
		}];

	}

	/**
	 * validation service
	 */
	function $ValidationProvider() {
		var validators = {}, register = this.register = function(name, factory) {
			if (validators.hasOwnProperty(name))
				throw vError(53, 'validator "{0}" has registerred, cannot override it', name);
			return validators[name] = newValidator(name, factory);
		};

		function newValidator(name, factory) {
			return function() {
				var v;
				if (isFunction(factory))
					v = _fastInvoke(factory, null, arguments);
				else if (isRegExp(factory) || (isString(factory) && factory.indexOf('/') === 0))
					v = patternFactory(factory);
				else {
					v = evaluateFactory(factory);
					v.$parse = true;
				}
				v.type = name;
				return v;
			};
		}


		Factory.$inject = ['$parse'];
		function Factory($parse) {
			get.validators = validators;
			get.use = function(ctrl, fn) {
				var validatorFn = fn, args, type = fn.type;
				if (isString(fn)) {
					args = arguments.length > 2 ? sliceArgs(arguments, 2) : [];
					if (fn.charAt(0) === ':') {
						validatorFn = newValidator(fn.substring(1), args[0]);
					} else {
						validatorFn = get(fn);
					}
					validatorFn = _fastInvoke(validatorFn, null, args);
					type = validatorFn.type;
					if (validatorFn.$parse)
						validatorFn = validatorFn($parse);
				}
				if (isFunction(validatorFn) || isArray(validatorFn)) {
					setupValidation(type, validatorFn, ctrl, ctrl.$parsers, ctrl.$$parsers, null);
					setupValidation(type, validatorFn, ctrl, ctrl.$formatters, ctrl.$$formatters, '');
				} else {
					if (validatorFn.parse)
						setupValidation(type, validatorFn.parse, ctrl, ctrl.$parsers, ctrl.$$parsers, null);
					if (validatorFn.format)
						setupValidation(type, validatorFn.format, ctrl, ctrl.$formatters, ctrl.$$formatters, '');
				}
			};

			function setupValidation(key, validatorFn, ctrl, holder, $holder, emptyValue) {
				var fn = validatorFn;
				if (isArray(validatorFn))
					fn = validatorFn[validatorFn.length - 1];
				var validateFn = function(valueToValidate) {
					var empty = isEmpty(valueToValidate), val;
					if (empty) {// un process validation
						ctrl.$setValidity(key, null);
						return emptyValue;
					} else if (( val = _fastInvoke(fn, null, arguments)) !== undefined) {// valid
						ctrl.$setValidity(key, true);
						return val;
					} else {
						ctrl.$setValidity(key, false);
						return valueToValidate;
					}
				};

				if (!isArray(validatorFn))
					holder.push(validateFn);
				else {
					// need copy
					var copy = [];
					forEach(validatorFn, function(value) {
						copy.push(value);
					});
					copy[validatorFn.length - 1] = validateFn;
					$holder.push(copy);
				}
			}

			function get(name) {
				if (!validators.hasOwnProperty(name))
					throw vError(54, 'no validator: {0}', name);
				return validators[name];
			}

			return get;

		}


		this.$get = Factory;

		function evaluateFactory(exp) {
			return function($parse) {
				if (isString(exp) && exp.match(/^\((.*)\)$/))
					exp = exp.substr(1, exp.length - 2);
				var expression = $parse(exp);
				expression.exp = exp;
				return ['$value', '$scope',
				function($value, $scope) {
					var ret = expression($scope, {
						$value : $value
					});
					return ret ? $value : undefined;
				}];
			};
		}

		function patternFactory(regexp) {
			var pattern = regexp;
			if (isString(regexp) && regexp.match(/^\/(.*)\/$/)) {
				regexp = regexp.substr(1, regexp.length - 2);
				pattern = (new RegExp(regexp));
			}
			return function(value) {
				var exp = pattern, match;
				match = exp.test(value);
				return match ? value : undefined;
			};
		}

		register('evaluate', evaluateFactory);

		// pattern
		register('pattern', patternFactory);

		register('minlength', function(minlength) {
			return function(value) {
				return (value.length >= minlength) ? value : undefined;
			};
		});

		register('maxlength', function(maxlength) {
			return function(value) {
				return (value.length <= maxlength) ? value : undefined;
			};
		});

		var NUMBER_REGEXP = /^\s*(\-|\+)?(\d+|(\d*(\.\d*)))\s*$/;
		register('number', function() {
			return {
				parse : function(value) {
					if (NUMBER_REGEXP.test(value)) {
						return parseFloat(value);
					} else {
						return undefined;
					}
				},
				format : function(value) {
					return '' + value;
				}
			};
		});

		register('min', function(min) {
			return function(value) {
				return (isNumber(value) && value >= min) ? value : undefined;
			};
		});

		register('max', function(max) {
			return function(value) {
				return (isNumber(value) && value <= max) ? value : undefined;
			};
		});

		// regex alias
		register('url', /^(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?$/);
		register('email', /^[A-Za-z0-9\._%+\-]+@[A-Za-z0-9\.\-]+\.[A-Za-z]{2,4}$/);
	}

	////////////////////////////////
	// Filters
	///////////////////////////////

	function vxSetupFilters() {
		var mod = vx.module('v');
		/**
		 * @vxdoc filter
		 * @name vx.filter:lowercase
		 * @function
		 * @description
		 * Converts string to lowercase.
		 * @see vx.lowercase
		 */
		mod.filter('lowercase', valueFn(lowercase));
		/**
		 * @vxdoc filter
		 * @name vx.filter:uppercase
		 * @function
		 * @description
		 * Converts string to uppercase.
		 * @see vx.uppercase
		 */
		mod.filter('uppercase', valueFn(uppercase));

		mod.filter('currency', currencyFilter);
		mod.filter('date', dateFilter);
		mod.filter('filter', filterFilter);
		mod.filter('json', jsonFilter);
		mod.filter('limitTo', limitToFilter);
		mod.filter('number', numberFilter);
		mod.filter('orderBy', orderByFilter);
	}

	/**
	 * @vxdoc filter
	 * @name vx.filter:filter
	 * @function
	 *
	 * @description
	 * Selects a subset of items from `array` and returns it as a new array.
	 *
	 * Note: This function is used to augment the `Array` type in VX expressions. See
	 * {@link vx.$filter} for more information about VX arrays.
	 *
	 * @param {Array} array The source array.
	 * @param {string|Object|function()} expression The predicate to be used for selecting items from
	 *   `array`.
	 *
	 *   Can be one of:
	 *
	 *   - `string`: Predicate that results in a substring match using the value of `expression`
	 *     string. All strings or objects with string properties in `array` that contain this string
	 *     will be returned. The predicate can be negated by prefixing the string with `!`.
	 *
	 *   - `Object`: A pattern object can be used to filter specific properties on objects contained
	 *     by `array`. For example `{name:"M", phone:"1"}` predicate will return an array of items
	 *     which have property `name` containing "M" and property `phone` containing "1". A special
	 *     property name `$` can be used (as in `{$:"text"}`) to accept a match against any
	 *     property of the object. That's equivalent to the simple substring match with a `string`
	 *     as described above.
	 *
	 *   - `function`: A predicate function can be used to write arbitrary filters. The function is
	 *     called for each element of `array`. The final result is an array of those elements that
	 *     the predicate returned true for.
	 *
	 * @param {function(expected, actual)|true|undefined} comparator Comparator which is used in
	 *     determining if the expected value (from the filter expression) and actual value (from
	 *     the object in the array) should be considered a match.
	 *
	 *   Can be one of:
	 *
	 *     - `function(expected, actual)`:
	 *       The function will be given the object value and the predicate value to compare and
	 *       should return true if the item should be included in filtered result.
	 *
	 *     - `true`: A shorthand for `function(expected, actual) { return vx.equals(expected, actual)}`.
	 *       this is essentially strict comparison of expected and actual.
	 *
	 *     - `false|undefined`: A short hand for a function which will look for a substring match in case
	 *       insensitive way.
	 *
	 * @example
	 <doc:example>
	 <doc:source>
	 <div v-init="friends = [{name:'John', phone:'555-1276'},
	 {name:'Mary', phone:'800-BIG-MARY'},
	 {name:'Mike', phone:'555-4321'},
	 {name:'Adam', phone:'555-5678'},
	 {name:'Julie', phone:'555-8765'},
	 {name:'Juliette', phone:'555-5678'}]"></div>

	 Search: <input v-model="searchText">
	 <table id="searchTextResults">
	 <tr><th>Name</th><th>Phone</th></tr>
	 <tr v-repeat="friend in friends | filter:searchText">
	 <td>{{friend.name}}</td>
	 <td>{{friend.phone}}</td>
	 </tr>
	 </table>
	 <hr>
	 Any: <input v-model="search.$"> <br>
	 Name only <input v-model="search.name"><br>
	 Phone only <input v-model="search.phone"><br>
	 Equality <input type="checkbox" v-model="strict"><br>
	 <table id="searchObjResults">
	 <tr><th>Name</th><th>Phone</th></tr>
	 <tr v-repeat="friend in friends | filter:search:strict">
	 <td>{{friend.name}}</td>
	 <td>{{friend.phone}}</td>
	 </tr>
	 </table>
	 </doc:source>
	 <doc:scenario>
	 it('should search across all fields when filtering with a string', function() {
	 input('searchText').enter('m');
	 expect(repeater('#searchTextResults tr', 'friend in friends').column('friend.name')).
	 toEqual(['Mary', 'Mike', 'Adam']);

	 input('searchText').enter('76');
	 expect(repeater('#searchTextResults tr', 'friend in friends').column('friend.name')).
	 toEqual(['John', 'Julie']);
	 });

	 it('should search in specific fields when filtering with a predicate object', function() {
	 input('search.$').enter('i');
	 expect(repeater('#searchObjResults tr', 'friend in friends').column('friend.name')).
	 toEqual(['Mary', 'Mike', 'Julie', 'Juliette']);
	 });
	 it('should use a equal comparison when comparator is true', function() {
	 input('search.name').enter('Julie');
	 input('strict').check();
	 expect(repeater('#searchObjResults tr', 'friend in friends').column('friend.name')).
	 toEqual(['Julie']);
	 });
	 </doc:scenario>
	 </doc:example>
	 */
	function filterFilter() {
		return function(array, expression, comperator) {
			if (!isArray(array))
				return array;
			var predicates = [];
			predicates.check = function(value) {
				for (var j = 0; j < predicates.length; j++) {
					if (!predicates[j](value)) {
						return false;
					}
				}
				return true;
			};
			switch(typeof comperator) {
				case "function":
					break;
				case "boolean":
					if (comperator === true) {
						comperator = function(obj, text) {
							return vx.equals(obj, text);
						};
						break;
					}
				/* falls through */
				default:
					comperator = function(obj, text) {
						text = ('' + text).toLowerCase();
						return ('' + obj).toLowerCase().indexOf(text) > -1;
					};
			}
			var search = function(obj, text) {
				if ( typeof text == 'string' && text.charAt(0) === '!') {
					return !search(obj, text.substr(1));
				}
				switch (typeof obj) {
					case "boolean":
					case "number":
					case "string":
						return comperator(obj, text);
					case "object":
						if (( typeof text) == "object")
							return comperator(obj, text);
						for (var objKey in obj) {
							if (objKey.charAt(0) !== '$' && search(obj[objKey], text)) {
								return true;
							}
						}
						return false;
					case "array":
						for (var i = 0; i < obj.length; i++) {
							if (search(obj[i], text)) {
								return true;
							}
						}
						return false;
					default:
						return false;
				}
			};
			/*jshint loopfunc:true*/
			switch (typeof expression) {
				case "boolean":
				case "number":
				case "string":
					expression = {
						$ : expression
					};
				/* falls through */
				case "object":
					for (var key in expression) {
						if (key == '$') {
							(function() {
								if (!expression[key])
									return;
								var path = key;
								predicates.push(function(value) {
									return search(value, expression[path]);
								});
							})();
						} else {
							(function() {
								if (!expression[key])
									return;
								var path = key;
								predicates.push(function(value) {
									return search(getter(value, path), expression[path]);
								});
							})();
						}
					}
					break;
				case 'function':
					predicates.push(expression);
					break;
				default:
					return array;
			}
			var filtered = [];
			for (var j = 0; j < array.length; j++) {
				var value = array[j];
				if (predicates.check(value)) {
					filtered.push(value);
				}
			}
			return filtered;
		};
	}

	/**
	 * @vxdoc filter
	 * @name vx.filter:currency
	 * @function
	 *
	 * @description
	 * Formats a number as a currency (ie $1,234.56). When no currency symbol is provided, default
	 * symbol for current locale is used.
	 *
	 * @param {number} amount Input to filter.
	 * @param {string=} symbol Currency symbol or identifier to be displayed.
	 * @returns {string} Formatted number.
	 *
	 *
	 * @example
	 <doc:example>
	 <doc:source>
	 <script>
	 function Ctrl($scope) {
	 $scope.amount = 1234.56;
	 }
	 </script>
	 <div v-controller="Ctrl">
	 <input type="number" v-model="amount"> <br>
	 default currency symbol ($): {{amount | currency}}<br>
	 custom currency identifier (USD$): {{amount | currency:"USD$"}}
	 </div>
	 </doc:source>
	 <doc:scenario>
	 it('should init with 1234.56', function() {
	 expect(binding('amount | currency')).toBe('$1,234.56');
	 expect(binding('amount | currency:"USD$"')).toBe('USD$1,234.56');
	 });
	 it('should update', function() {
	 input('amount').enter('-1234');
	 expect(binding('amount | currency')).toBe('($1,234.00)');
	 expect(binding('amount | currency:"USD$"')).toBe('(USD$1,234.00)');
	 });
	 </doc:scenario>
	 </doc:example>
	 */
	currencyFilter.$inject = ['$locale'];
	function currencyFilter($locale) {
		var formats = $locale.NUMBER_FORMATS;
		return function(amount, currencySymbol) {
			if (isUndefined(currencySymbol))
				currencySymbol = formats.CURRENCY_SYM;
			return formatNumber(amount, formats.PATTERNS[1], formats.GROUP_SEP, formats.DECIMAL_SEP, 2).replace(/\u00A4/g, currencySymbol);
		};
	}

	function formatNumber(number, pattern, groupSep, decimalSep, fractionSize) {
		if (isNaN(number) || !isFinite(number))
			return '';

		var isNegative = number < 0;
		number = Math.abs(number);
		var numStr = number + '', formatedText = '', parts = [];

		var hasExponent = false;
		if (numStr.indexOf('e') !== -1) {
			var match = numStr.match(/([\d\.]+)e(-?)(\d+)/);
			if (match && match[2] == '-' && match[3] > fractionSize + 1) {
				numStr = '0';
			} else {
				formatedText = numStr;
				hasExponent = true;
			}
		}
		if (!hasExponent) {
			var fractionLen = (numStr.split(decimalSep)[1] || '').length;

			// determine fractionSize if it is not specified
			if (isUndefined(fractionSize)) {
				fractionSize = Math.min(Math.max(pattern.minFrac, fractionLen), pattern.maxFrac);
			}

			var pow = Math.pow(10, fractionSize);
			number = Math.round(number * pow) / pow;
			var fraction = ('' + number).split(decimalSep);
			var whole = fraction[0];
			fraction = fraction[1] || '';

			var pos = 0, lgroup = pattern.lgSize, group = pattern.gSize, i;

			if (whole.length >= (lgroup + group)) {
				pos = whole.length - lgroup;
				for ( i = 0; i < pos; i++) {
					if ((pos - i) % group === 0 && i !== 0) {
						formatedText += groupSep;
					}
					formatedText += whole.charAt(i);
				}
			}

			for ( i = pos; i < whole.length; i++) {
				if ((whole.length - i) % lgroup === 0 && i !== 0) {
					formatedText += groupSep;
				}
				formatedText += whole.charAt(i);
			}

			// format fraction part.
			while (fraction.length < fractionSize) {
				fraction += '0';
			}

			if (fractionSize && fractionSize !== "0")
				formatedText += decimalSep + fraction.substr(0, fractionSize);
		}

		parts.push( isNegative ? pattern.negPre : pattern.posPre);
		parts.push(formatedText);
		parts.push( isNegative ? pattern.negSuf : pattern.posSuf);
		return parts.join('');
	}

	/**
	 * @vxdoc filter
	 * @name vx.filter:number
	 * @function
	 *
	 * @description
	 * Formats a number as text.
	 *
	 * If the input is not a number an empty string is returned.
	 *
	 * @param {number|string} number Number to format.
	 * @param {(number|string)=} [fractionSize=2] Number of decimal places to round the number to.
	 * @returns {string} Number rounded to decimalPlaces and places a “,” after each third digit.
	 *
	 * @example
	 <doc:example>
	 <doc:source>
	 <script>
	 function Ctrl($scope) {
	 $scope.val = 1234.56789;
	 }
	 </script>
	 <div v-controller="Ctrl">
	 Enter number: <input v-model='val'><br>
	 Default formatting: {{val | number}}<br>
	 No fractions: {{val | number:0}}<br>
	 Negative number: {{-val | number:4}}
	 </div>
	 </doc:source>
	 <doc:scenario>
	 it('should format numbers', function() {
	 expect(binding('val | number')).toBe('1,234.568');
	 expect(binding('val | number:0')).toBe('1,235');
	 expect(binding('-val | number:4')).toBe('-1,234.5679');
	 });

	 it('should update', function() {
	 input('val').enter('3374.333');
	 expect(binding('val | number')).toBe('3,374.333');
	 expect(binding('val | number:0')).toBe('3,374');
	 expect(binding('-val | number:4')).toBe('-3,374.3330');
	 });
	 </doc:scenario>
	 </doc:example>
	 */

	numberFilter.$inject = ['$locale'];
	function numberFilter($locale) {
		var formats = $locale.NUMBER_FORMATS;
		return function(number, fractionSize) {
			return formatNumber(number, formats.PATTERNS[0], formats.GROUP_SEP, formats.DECIMAL_SEP, fractionSize);
		};
	}

	/**
	 * @vxdoc filter
	 * @name vx.filter:date
	 * @function
	 *
	 * @description
	 *   Formats `date` to a string based on the requested `format`.
	 *
	 *   `format` string can be composed of the following elements:
	 *
	 *   * `'yyyy'`: 4 digit representation of year (e.g. AD 1 => 0001, AD 2010 => 2010)
	 *   * `'yy'`: 2 digit representation of year, padded (00-99). (e.g. AD 2001 => 01, AD 2010 => 10)
	 *   * `'y'`: 1 digit representation of year, e.g. (AD 1 => 1, AD 199 => 199)
	 *   * `'MMMM'`: Month in year (January-December)
	 *   * `'MMM'`: Month in year (Jan-Dec)
	 *   * `'MM'`: Month in year, padded (01-12)
	 *   * `'M'`: Month in year (1-12)
	 *   * `'dd'`: Day in month, padded (01-31)
	 *   * `'d'`: Day in month (1-31)
	 *   * `'EEEE'`: Day in Week,(Sunday-Saturday)
	 *   * `'EEE'`: Day in Week, (Sun-Sat)
	 *   * `'HH'`: Hour in day, padded (00-23)
	 *   * `'H'`: Hour in day (0-23)
	 *   * `'hh'`: Hour in am/pm, padded (01-12)
	 *   * `'h'`: Hour in am/pm, (1-12)
	 *   * `'mm'`: Minute in hour, padded (00-59)
	 *   * `'m'`: Minute in hour (0-59)
	 *   * `'ss'`: Second in minute, padded (00-59)
	 *   * `'s'`: Second in minute (0-59)
	 *   * `'.sss' or ',sss'`: Millisecond in second, padded (000-999)
	 *   * `'a'`: am/pm marker
	 *   * `'Z'`: 4 digit (+sign) representation of the timezone offset (-1200-+1200)
	 *
	 *   `format` string can also be one of the following predefined
	 *   {@link guide/i18n localizable formats}:
	 *
	 *   * `'medium'`: equivalent to `'MMM d, y h:mm:ss a'` for en_US locale
	 *     (e.g. Sep 3, 2010 12:05:08 pm)
	 *   * `'short'`: equivalent to `'M/d/yy h:mm a'` for en_US  locale (e.g. 9/3/10 12:05 pm)
	 *   * `'fullDate'`: equivalent to `'EEEE, MMMM d,y'` for en_US  locale
	 *     (e.g. Friday, September 3, 2010)
	 *   * `'longDate'`: equivalent to `'MMMM d, y'` for en_US  locale (e.g. September 3, 2010
	 *   * `'mediumDate'`: equivalent to `'MMM d, y'` for en_US  locale (e.g. Sep 3, 2010)
	 *   * `'shortDate'`: equivalent to `'M/d/yy'` for en_US locale (e.g. 9/3/10)
	 *   * `'mediumTime'`: equivalent to `'h:mm:ss a'` for en_US locale (e.g. 12:05:08 pm)
	 *   * `'shortTime'`: equivalent to `'h:mm a'` for en_US locale (e.g. 12:05 pm)
	 *
	 *   `format` string can contain literal values. These need to be quoted with single quotes (e.g.
	 *   `"h 'in the morning'"`). In order to output single quote, use two single quotes in a sequence
	 *   (e.g. `"h o''clock"`).
	 *
	 * @param {(Date|number|string)} date Date to format either as Date object, milliseconds (string or
	 *    number) or various ISO 8601 datetime string formats (e.g. yyyy-MM-ddTHH:mm:ss.SSSZ and its
	 *    shorter versions like yyyy-MM-ddTHH:mmZ, yyyy-MM-dd or yyyyMMddTHHmmssZ). If no timezone is
	 *    specified in the string input, the time is considered to be in the local timezone.
	 * @param {string=} format Formatting rules (see Description). If not specified,
	 *    `mediumDate` is used.
	 * @returns {string} Formatted string or the input if input is not recognized as date/millis.
	 *
	 * @example
	 <doc:example>
	 <doc:source>
	 <span v-non-bindable>{{1288323623006 | date:'medium'}}</span>:
	 {{1288323623006 | date:'medium'}}<br>
	 <span v-non-bindable>{{1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'}}</span>:
	 {{1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'}}<br>
	 <span v-non-bindable>{{1288323623006 | date:'MM/dd/yyyy @ h:mma'}}</span>:
	 {{'1288323623006' | date:'MM/dd/yyyy @ h:mma'}}<br>
	 </doc:source>
	 <doc:scenario>
	 it('should format date', function() {
	 expect(binding("1288323623006 | date:'medium'")).
	 toMatch(/Oct 2\d, 2010 \d{1,2}:\d{2}:\d{2} (AM|PM)/);
	 expect(binding("1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'")).
	 toMatch(/2010\-10\-2\d \d{2}:\d{2}:\d{2} (\-|\+)?\d{4}/);
	 expect(binding("'1288323623006' | date:'MM/dd/yyyy @ h:mma'")).
	 toMatch(/10\/2\d\/2010 @ \d{1,2}:\d{2}(AM|PM)/);
	 });
	 </doc:scenario>
	 </doc:example>
	 */
	dateFilter.$inject = ['$locale'];
	function dateFilter($locale) {

		var R_ISO8601_STR = /^(\d{4})-?(\d\d)-?(\d\d)(?:T(\d\d)(?::?(\d\d)(?::?(\d\d)(?:\.(\d+))?)?)?(Z|([+\-])(\d\d):?(\d\d))?)?$/;
		//                                 1          2          3           4             5            6            7              8  9      10        11
		function jsonStringToDate(string) {
			var match;
			/*jshint boss:true*/
			if ( match = string.match(R_ISO8601_STR)) {
				var date = new Date(0), tzHour = 0, tzMin = 0, //
				dateSetter = match[8] ? date.setUTCFullYear : date.setFullYear, timeSetter = match[8] ? date.setUTCHours : date.setHours;
				if (match[9]) {
					tzHour = int(match[9] + match[10]);
					tzMin = int(match[9] + match[11]);
				}
				dateSetter.call(date, int(match[1]), int(match[2]) - 1, int(match[3]));
				var h = int(match[4] || 0) - tzHour;
				var m = int(match[5] || 0) - tzMin;
				var s = int(match[6] || 0);
				var ms = Math.round(parseFloat('0.' + (match[7] || 0)) * 1000);
				timeSetter.call(date, h, m, s, ms);
				return date;
			}
			return string;
		}

		function dateGetter(name, size, offset, trim) {
			offset = offset || 0;
			return function(date) {
				var value = date['get' + name]();
				if (offset > 0 || value > -offset)
					value += offset;
				if (value === 0 && offset == -12)
					value = 12;
				return padNumber(value, size, trim);
			};
		}

		function dateStrGetter(name, shortForm) {
			return function(date, formats) {
				var value = date['get' + name]();
				var get = uppercase( shortForm ? ('SHORT' + name) : name);

				return formats[get][value];
			};
		}

		function timeZoneGetter(date) {
			var zone = -1 * date.getTimezoneOffset();
			var paddedZone = (zone >= 0) ? "+" : "";
			paddedZone += padNumber(Math[zone > 0 ? 'floor' : 'ceil'](zone / 60), 2) + padNumber(Math.abs(zone % 60), 2);
			return paddedZone;
		}

		function ampmGetter(date, formats) {
			return date.getHours() < 12 ? formats.AMPMS[0] : formats.AMPMS[1];
		}

		var DATE_FORMATS = {
			yyyy : dateGetter('FullYear', 4),
			yy : dateGetter('FullYear', 2, 0, true),
			y : dateGetter('FullYear', 1),
			MMMM : dateStrGetter('Month'),
			MMM : dateStrGetter('Month', true),
			MM : dateGetter('Month', 2, 1),
			M : dateGetter('Month', 1, 1),
			dd : dateGetter('Date', 2),
			d : dateGetter('Date', 1),
			HH : dateGetter('Hours', 2),
			H : dateGetter('Hours', 1),
			hh : dateGetter('Hours', 2, -12),
			h : dateGetter('Hours', 1, -12),
			mm : dateGetter('Minutes', 2),
			m : dateGetter('Minutes', 1),
			ss : dateGetter('Seconds', 2),
			s : dateGetter('Seconds', 1),
			// while ISO 8601 requires fractions to be prefixed with `.` or `,`
			// we can be just safely rely on using `sss` since we currently don't support single or two digit fractions
			sss : dateGetter('Milliseconds', 3),
			EEEE : dateStrGetter('Day'),
			EEE : dateStrGetter('Day', true),
			a : ampmGetter,
			Z : timeZoneGetter
		};

		var DATE_FORMATS_SPLIT = /((?:[^yMdHhmsaZE']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|d+|H+|h+|m+|s+|a|Z))(.*)/, NUMBER_STRING = /^\d+$/;

		return function(date, format) {
			var text = '', parts = [], fn, match;
			format = format || 'mediumDate';
			format = $locale.DATETIME_FORMATS[format] || format;
			if (isString(date)) {
				if (NUMBER_STRING.test(date)) {
					date = int(date);
				} else {
					date = jsonStringToDate(date);
				}
			}

			if (isNumber(date)) {
				date = new Date(date);
			}

			if (!isDate(date)) {
				return date;
			}

			while (format) {
				match = DATE_FORMATS_SPLIT.exec(format);
				if (match) {
					parts = concat(parts, match, 1);
					format = parts.pop();
				} else {
					parts.push(format);
					format = null;
				}
			}

			forEach(parts, function(value) {
				fn = DATE_FORMATS[value];
				text += fn ? fn(date, $locale.DATETIME_FORMATS) : value.replace(/(^'|'$)/g, '').replace(/''/g, "'");
			});
			return text;
		};
	}

	/**
	 * @vxdoc filter
	 * @name vx.filter:json.json
	 * @function
	 *
	 * @description
	 *   Allows you to convert a JavaScript object into JSON string.
	 *
	 *   This filter is mostly useful for debugging. When using the double curly {{value}} notation
	 *   the binding is automatically converted to JSON.
	 *
	 * @param {*} object Any JavaScript object (including arrays and primitive types) to filter.
	 * @returns {string} JSON string.
	 *
	 *
	 * @example:
	 <doc:example>
	 <doc:source>
	 <pre>{{ {'name':'value'} | json.json }}</pre>
	 </doc:source>
	 <doc:scenario>
	 it('should jsonify filtered objects', function() {
	 expect(binding("{'name':'value'}")).toMatch(/\{\n  "name": ?"value"\n}/);
	 });
	 </doc:scenario>
	 </doc:example>
	 *
	 */
	function jsonFilter() {
		return function(object) {
			return toJson(object, true);
		};
	}

	/**
	 * @vxdoc function
	 * @name vx.filter:limitTo
	 * @function
	 *
	 * @description
	 * Creates a new array or string containing only a specified number of elements. The elements
	 * are taken from either the beginning or the end of the source array or string, as specified by the
	 * value and sign (positive or negative) of `limit`.
	 *
	 * Note: This function is used to augment the `Array` type in VX expressions. See
	 * {@link vx.$filter} for more information about VX arrays.
	 *
	 * @param {Array|string} input Source array or string to be limited.
	 * @param {string|number} limit The length of the returned array or string. If the `limit` number is
	 *     positive, `limit` number of items from the beginning of the source array/string are copied.
	 *     If the number is negative, `limit` number  of items from the end of the source array/string are
	 *     copied. The `limit` will be trimmed if it exceeds `array.length`
	 * @returns {Array|string} A new sub-array or substring of length `limit` or less if input array/string had less than `limit`
	 *     elements.
	 *
	 * @example
	 <doc:example>
	 <doc:source>
	 <script>
	 function Ctrl($scope) {
	 $scope.numbers = [1,2,3,4,5,6,7,8,9];
	 $scope.letters = "abcdefghi";
	 $scope.numLimit = 3;
	 $scope.letterLimit = 3;
	 }
	 </script>
	 <div v-controller="Ctrl">
	 Limit {{numbers}} to: <input type="integer" v-model="numLimit">
	 <p>Output numbers: {{ numbers | limitTo:numLimit }}</p>
	 Limit {{letters}} to: <input type="integer" v-model="letterLimit">
	 <p>Output letters: {{ letters | limitTo:letterLimit }}</p>
	 </div>
	 </doc:source>
	 <doc:scenario>
	 it('should limit the number array to first three items', function() {
	 expect(element('.doc-example-live input[v-model=numLimit]').val()).toBe('3');
	 expect(element('.doc-example-live input[v-model=letterLimit]').val()).toBe('3');
	 expect(binding('numbers | limitTo:numLimit')).toEqual('[1,2,3]');
	 expect(binding('letters | limitTo:letterLimit')).toEqual('abc');
	 });

	 it('should update the output when -3 is entered', function() {
	 input('numLimit').enter(-3);
	 input('letterLimit').enter(-3);
	 expect(binding('numbers | limitTo:numLimit')).toEqual('[7,8,9]');
	 expect(binding('letters | limitTo:letterLimit')).toEqual('ghi');
	 });

	 it('should not exceed the maximum size of input array', function() {
	 input('numLimit').enter(100);
	 input('letterLimit').enter(100);
	 expect(binding('numbers | limitTo:numLimit')).toEqual('[1,2,3,4,5,6,7,8,9]');
	 expect(binding('letters | limitTo:letterLimit')).toEqual('abcdefghi');
	 });
	 </doc:scenario>
	 </doc:example>
	 */
	function limitToFilter() {
		return function(input, limit) {
			if (!isArray(input) && !isString(input))
				return input;

			limit = int(limit);

			if (isString(input)) {
				//NaN check on limit
				if (limit) {
					return limit >= 0 ? input.slice(0, limit) : input.slice(limit, input.length);
				} else {
					return "";
				}
			}

			var out = [], i, n;

			// if abs(limit) exceeds maximum length, trim it
			if (limit > input.length)
				limit = input.length;
			else if (limit < -input.length)
				limit = -input.length;

			if (limit > 0) {
				i = 0;
				n = limit;
			} else {
				i = input.length + limit;
				n = input.length;
			}

			for (; i < n; i++) {
				out.push(input[i]);
			}

			return out;
		};
	}

	/**
	 * @vxdoc function
	 * @name vx.filter:orderBy
	 * @function
	 *
	 * @description
	 * Orders a specified `array` by the `expression` predicate.
	 *
	 * Note: this function is used to augment the `Array` type in VX expressions. See
	 * {@link vx.$filter} for more information about VX arrays.
	 *
	 * @param {Array} array The array to sort.
	 * @param {function(*)|string|Array.<(function(*)|string)>} expression A predicate to be
	 *    used by the comparator to determine the order of elements.
	 *
	 *    Can be one of:
	 *
	 *    - `function`: Getter function. The result of this function will be sorted using the
	 *      `<`, `=`, `>` operator.
	 *    - `string`: An VX expression which evaluates to an object to order by, such as 'name'
	 *      to sort by a property called 'name'. Optionally prefixed with `+` or `-` to control
	 *      ascending or descending sort order (for example, +name or -name).
	 *    - `Array`: An array of function or string predicates. The first predicate in the array
	 *      is used for sorting, but when two items are equivalent, the next predicate is used.
	 *
	 * @param {boolean=} reverse Reverse the order the array.
	 * @returns {Array} Sorted copy of the source array.
	 *
	 * @example
	 <doc:example>
	 <doc:source>
	 <script>
	 function Ctrl($scope) {
	 $scope.friends =
	 [{name:'John', phone:'555-1212', age:10},
	 {name:'Mary', phone:'555-9876', age:19},
	 {name:'Mike', phone:'555-4321', age:21},
	 {name:'Adam', phone:'555-5678', age:35},
	 {name:'Julie', phone:'555-8765', age:29}]
	 $scope.predicate = '-age';
	 }
	 </script>
	 <div v-controller="Ctrl">
	 <pre>Sorting predicate = {{predicate}}; reverse = {{reverse}}</pre>
	 <hr/>
	 [ <a href="" v-click="predicate=''">unsorted</a> ]
	 <table class="friend">
	 <tr>
	 <th><a href="" v-click="predicate = 'name'; reverse=false">Name</a>
	 (<a href v-click="predicate = '-name'; reverse=false">^</a>)</th>
	 <th><a href="" v-click="predicate = 'phone'; reverse=!reverse">Phone Number</a></th>
	 <th><a href="" v-click="predicate = 'age'; reverse=!reverse">Age</a></th>
	 </tr>
	 <tr v-repeat="friend in friends | orderBy:predicate:reverse">
	 <td>{{friend.name}}</td>
	 <td>{{friend.phone}}</td>
	 <td>{{friend.age}}</td>
	 </tr>
	 </table>
	 </div>
	 </doc:source>
	 <doc:scenario>
	 it('should be reverse ordered by aged', function() {
	 expect(binding('predicate')).toBe('-age');
	 expect(repeater('table.friend', 'friend in friends').column('friend.age')).
	 toEqual(['35', '29', '21', '19', '10']);
	 expect(repeater('table.friend', 'friend in friends').column('friend.name')).
	 toEqual(['Adam', 'Julie', 'Mike', 'Mary', 'John']);
	 });

	 it('should reorder the table when user selects different predicate', function() {
	 element('.doc-example-live a:contains("Name")').click();
	 expect(repeater('table.friend', 'friend in friends').column('friend.name')).
	 toEqual(['Adam', 'John', 'Julie', 'Mary', 'Mike']);
	 expect(repeater('table.friend', 'friend in friends').column('friend.age')).
	 toEqual(['35', '10', '29', '19', '21']);

	 element('.doc-example-live a:contains("Phone")').click();
	 expect(repeater('table.friend', 'friend in friends').column('friend.phone')).
	 toEqual(['555-9876', '555-8765', '555-5678', '555-4321', '555-1212']);
	 expect(repeater('table.friend', 'friend in friends').column('friend.name')).
	 toEqual(['Mary', 'Julie', 'Adam', 'Mike', 'John']);
	 });
	 </doc:scenario>
	 </doc:example>
	 */
	orderByFilter.$inject = ['$parse'];
	function orderByFilter($parse) {
		return function(array, sortPredicate, reverseOrder) {
			if (!isArray(array))
				return array;
			if (!sortPredicate)
				return array;
			sortPredicate = isArray(sortPredicate) ? sortPredicate : [sortPredicate];
			sortPredicate = map(sortPredicate, function(predicate) {
				var descending = false, get = predicate || identity;
				if (isString(predicate)) {
					if ((predicate.charAt(0) == '+' || predicate.charAt(0) == '-')) {
						descending = predicate.charAt(0) == '-';
						predicate = predicate.substring(1);
					}
					get = $parse(predicate);
				}
				return reverseComparator(function(a, b) {
					return compare(get(a), get(b));
				}, descending);
			});
			var arrayCopy = [];
			for (var i = 0; i < array.length; i++) {
				arrayCopy.push(array[i]);
			}
			return arrayCopy.sort(reverseComparator(comparator, reverseOrder));

			function comparator(o1, o2) {
				for (var i = 0; i < sortPredicate.length; i++) {
					var comp = sortPredicate[i](o1, o2);
					if (comp !== 0)
						return comp;
				}
				return 0;
			}

			function reverseComparator(comp, descending) {
				return toBoolean(descending) ? function(a, b) {
					return comp(b, a);
				} : comp;
			}

			function compare(v1, v2) {
				var t1 = typeof v1;
				var t2 = typeof v2;
				if (t1 == t2) {
					if (t1 == "string")
						v1 = v1.toLowerCase();
					if (t1 == "string")
						v2 = v2.toLowerCase();
					if (v1 === v2)
						return 0;
					return v1 < v2 ? -1 : 1;
				} else {
					return t1 < t2 ? -1 : 1;
				}
			}

		};
	}

	////////////////////////////////
	// Directives
	///////////////////////////////

	function vxSetupDirectives() {
		vx.module('v').directive({
			a : htmlAnchorDirective,
			input : inputDirective,
			textarea : inputDirective,
			select : selectDirective,
			option : optionDirective,
			button : inputDirective,
			//vVal : vValDirective,
			form : formDirective,
			script : scriptDirective,
			//style : styleDirective,

			//vCsp : vCspDirective,
			vBind : vBindDirective,
			//vBindHtml : vBindHtmlDirective,
			//vBindTemplate : vBindTemplateDirective,
			//vClass : vClassDirective,
			//vClassEven : vClassEvenDirective,
			//vClassOdd : vClassOddDirective,
			//vCloak : vCloakDirective,
			vController : vControllerDirective,
			//vForm : vFormDirective,
			vHide : vHideDirective,
			vInclude : vIncludeDirective,
			vInit : vInitDirective,
			//vNonBindable : vNonBindableDirective,
			vRepeat : vRepeatDirective,
			vShow : vShowDirective,
			vSubmit : vSubmitDirective,
			//vStyle : vStyleDirective,
			vIf : vIfDirective,
			//vSwitch : vSwitchDirective,
			//vSwitchWhen : vSwitchWhenDirective,
			//vSwitchDefault : vSwitchDefaultDirective,
			vOptions : vOptionsDirective,
			//vTransclude : vTranscludeDirective,
			vModel : vModelDirective,
			//vList : vListDirective,
			vChange : vChangeDirective,
			required : requiredDirective,
			vRequired : requiredDirective,
			//vValue : vValueDirective,
			vViewport : vViewportDirective,
			vPage : vPageDirective,
			vViewSetup : vViewSetupDirective,
			//vTarget : vTargetDirective,
			//vTrack : vTrackDirective
		}).directive(vEventDirectives).directive(vAttributeAliasDirectives);
	}

	/**
	 * @vxdoc directive
	 * @name vx.directive:vCsp
	 * @priority 1000
	 *
	 * @element html
	 * @description
	 * Enables [CSP (Content Security Policy)](https://developer.mozilla.org/en/Security/CSP) support.
	 *
	 * This is necessary when developing things like Google Chrome Extensions.
	 *
	 * CSP forbids apps to use `eval` or `Function(string)` generated functions (among other things).
	 * For us to be compatible, we just need to implement the "getterFn" in $parse without violating
	 * any of these restrictions.
	 *
	 * vx uses `Function(string)` generated functions as a speed optimization. By applying `vCsp`
	 * it is be possible to opt into the CSP compatible mode. When this mode is on, vx will
	 * evaluate all expressions up to 30% slower than in non-CSP mode, but no security violations will
	 * be raised.
	 *
	 * In order to use this feature put `vCsp` directive on the root element of the application.
	 *
	 * @example
	 * This example shows how to apply the `vCsp` directive to the `html` tag.
	 <pre>
	 <!doctype html>
	 <html v-app v-csp>
	 ...
	 ...
	 </html>
	 </pre>
	 */
	/*
	vCspDirective.$inject = ['$sniffer'];
	function vCspDirective($sniffer) {
		return {
			priority : 1000,
			compile : function() {
				$sniffer.csp = true;
			}
		};
	}
	*/

	/**
	 * @vxdoc directive
	 * @name vx.directive:vInit
	 *
	 * @description
	 * The `vInit` directive specifies initialization tasks to be executed
	 *  before the template enters execution mode during bootstrap.
	 *
	 * @element ANY
	 * @param {expression} vInit {@link guide/expression Expression} to eval.
	 *
	 * @example
	 <doc:example>
	 <doc:source>
	 <div v-init="greeting='Hello'; person='World'">
	 {{greeting}} {{person}}!
	 </div>
	 </doc:source>
	 <doc:scenario>
	 it('should check greeting', function() {
	 expect(binding('greeting')).toBe('Hello');
	 expect(binding('person')).toBe('World');
	 });
	 </doc:scenario>
	 </doc:example>
	 */
	vInitDirective.$inject = ['$$remote'];
	function vInitDirective($$remote) {
		return {
			restrict : 'AC',
			compile : function() {
				return {
					pre : function(scope, element, attrs) {
						scope.$eval(attrs.vInit, injectRemote(element, null, attrs.vInit, false, $$remote));
					}
				};
			}
		};
	}

	/**
	 * @vxdoc directive
	 * @name vx.directive:vController
	 *
	 * @description
	 * The `vController` directive assigns behavior to a scope. This is a key aspect of how vx
	 * supports the principles behind the Model-View-Controller design pattern.
	 *
	 * MVC components in vx:
	 *
	 * * Model — The Model is data in scope properties; scopes are attached to the DOM.
	 * * View — The template (HTML with data bindings) is rendered into the View.
	 * * Controller — The `vController` directive specifies a Controller class; the class has
	 *   methods that typically express the business logic behind the application.
	 *
	 * Note that an alternative way to define controllers is via the {@link vx.$route}
	 * service.
	 *
	 * @element ANY
	 * @scope
	 * @param {expression} vController Name of a globally accessible constructor function or an
	 *     {@link guide/expression expression} that on the current scope evaluates to a
	 *     constructor function. The controller instance can further be published into the scope
	 *     by adding `as localName` the controller name attribute.
	 *
	 * @example
	 * Here is a simple form for editing user contact information. Adding, removing, clearing, and
	 * greeting are methods declared on the controller (see source tab). These methods can
	 * easily be called from the vx markup. Notice that the scope becomes the `this` for the
	 * controller's instance. This allows for easy access to the view data from the controller. Also
	 * notice that any changes to the data are automatically reflected in the View without the need
	 * for a manual update.
	 <doc:example>
	 <doc:source>
	 <script>
	 function SettingsController1() {
	 this.name = "John Smith";
	 this.contacts = [
	 {type: 'phone', value: '408 555 1212'},
	 {type: 'email', value: 'john.smith@example.org'} ];
	 };

	 SettingsController1.prototype.greet = function() {
	 alert(this.name);
	 };

	 SettingsController1.prototype.addContact = function() {
	 this.contacts.push({type: 'email', value: 'yourname@example.org'});
	 };

	 SettingsController1.prototype.removeContact = function(contactToRemove) {
	 var index = this.contacts.indexOf(contactToRemove);
	 this.contacts.splice(index, 1);
	 };

	 SettingsController1.prototype.clearContact = function(contact) {
	 contact.type = 'phone';
	 contact.value = '';
	 };
	 </script>
	 <div id="ctrl-as-exmpl" v-controller="SettingsController1 as settings">
	 Name: <input type="text" v-model="settings.name"/>
	 [ <a href="" v-click="settings.greet()">greet</a> ]<br/>
	 Contact:
	 <ul>
	 <li v-repeat="contact in settings.contacts">
	 <select v-model="contact.type">
	 <option>phone</option>
	 <option>email</option>
	 </select>
	 <input type="text" v-model="contact.value"/>
	 [ <a href="" v-click="settings.clearContact(contact)">clear</a>
	 | <a href="" v-click="settings.removeContact(contact)">X</a> ]
	 </li>
	 <li>[ <a href="" v-click="settings.addContact()">add</a> ]</li>
	 </ul>
	 </div>
	 </doc:source>
	 <doc:scenario>
	 it('should check controller as', function() {
	 expect(element('#ctrl-as-exmpl>:input').val()).toBe('John Smith');
	 expect(element('#ctrl-as-exmpl li:nth-child(1) input').val())
	 .toBe('408 555 1212');
	 expect(element('#ctrl-as-exmpl li:nth-child(2) input').val())
	 .toBe('john.smith@example.org');

	 element('#ctrl-as-exmpl li:first a:contains("clear")').click();
	 expect(element('#ctrl-as-exmpl li:first input').val()).toBe('');

	 element('#ctrl-as-exmpl li:last a:contains("add")').click();
	 expect(element('#ctrl-as-exmpl li:nth-child(3) input').val())
	 .toBe('yourname@example.org');
	 });
	 </doc:scenario>
	 </doc:example>
	 <doc:example>
	 <doc:source>
	 <script>
	 function SettingsController2($scope) {
	 $scope.name = "John Smith";
	 $scope.contacts = [
	 {type:'phone', value:'408 555 1212'},
	 {type:'email', value:'john.smith@example.org'} ];

	 $scope.greet = function() {
	 alert(this.name);
	 };

	 $scope.addContact = function() {
	 this.contacts.push({type:'email', value:'yourname@example.org'});
	 };

	 $scope.removeContact = function(contactToRemove) {
	 var index = this.contacts.indexOf(contactToRemove);
	 this.contacts.splice(index, 1);
	 };

	 $scope.clearContact = function(contact) {
	 contact.type = 'phone';
	 contact.value = '';
	 };
	 }
	 </script>
	 <div id="ctrl-exmpl" v-controller="SettingsController2">
	 Name: <input type="text" v-model="name"/>
	 [ <a href="" v-click="greet()">greet</a> ]<br/>
	 Contact:
	 <ul>
	 <li v-repeat="contact in contacts">
	 <select v-model="contact.type">
	 <option>phone</option>
	 <option>email</option>
	 </select>
	 <input type="text" v-model="contact.value"/>
	 [ <a href="" v-click="clearContact(contact)">clear</a>
	 | <a href="" v-click="removeContact(contact)">X</a> ]
	 </li>
	 <li>[ <a href="" v-click="addContact()">add</a> ]</li>
	 </ul>
	 </div>
	 </doc:source>
	 <doc:scenario>
	 it('should check controller', function() {
	 expect(element('#ctrl-exmpl>:input').val()).toBe('John Smith');
	 expect(element('#ctrl-exmpl li:nth-child(1) input').val())
	 .toBe('408 555 1212');
	 expect(element('#ctrl-exmpl li:nth-child(2) input').val())
	 .toBe('john.smith@example.org');

	 element('#ctrl-exmpl li:first a:contains("clear")').click();
	 expect(element('#ctrl-exmpl li:first input').val()).toBe('');

	 element('#ctrl-exmpl li:last a:contains("add")').click();
	 expect(element('#ctrl-exmpl li:nth-child(3) input').val())
	 .toBe('yourname@example.org');
	 });
	 </doc:scenario>
	 </doc:example>

	 */
	function vControllerDirective() {
		return {
			scope : true,
			controller : '@'//XXX use attr v-controller as name
		};
	}

	/**
	 * @vxdoc directive
	 * @name vx.directive:vBind
	 *
	 * @description
	 * The `vBind` attribute tells VX to replace the text content of the specified HTML element
	 * with the value of a given expression, and to update the text content when the value of that
	 * expression changes.
	 *
	 * Typically, you don't use `vBind` directly, but instead you use the double curly markup like
	 * `{{ expression }}` which is similar but less verbose.
	 *
	 * One scenario in which the use of `vBind` is preferred over `{{ expression }}` binding is when
	 * it's desirable to put bindings into template that is momentarily displayed by the browser in its
	 * raw state before VX compiles it. Since `vBind` is an element attribute, it makes the
	 * bindings invisible to the user while the page is loading.
	 *
	 * An alternative solution to this problem would be using the
	 * {@link vx.directive:vCloak vCloak} directive.
	 *
	 *
	 * @element ANY
	 * @param {expression} vBind {@link guide/expression Expression} to evaluate.
	 *
	 * @example
	 * Enter a name in the Live Preview text box; the greeting below the text box changes instantly.
	 <doc:example>
	 <doc:source>
	 <script>
	 function Ctrl($scope) {
	 $scope.name = 'Whirled';
	 }
	 </script>
	 <div v-controller="Ctrl">
	 Enter name: <input type="text" v-model="name"><br>
	 Hello <span v-bind="name"></span>!
	 </div>
	 </doc:source>
	 <doc:scenario>
	 it('should check v-bind', function() {
	 expect(using('.doc-example-live').binding('name')).toBe('Whirled');
	 using('.doc-example-live').input('name').enter('world');
	 expect(using('.doc-example-live').binding('name')).toBe('world');
	 });
	 </doc:scenario>
	 </doc:example>
	 */
	function vBindDirective() {
		return {
			restrict : 'AC',
			link : function(scope, element, attr) {
				element.addClass('v-binding').data('$binding', attr.vBind);
				scope.$watch(attr.vBind, function vBindWatchAction(value) {
					element.text(value === undefined ? '' : value);
				});
			}
		};
	}
	
	/**
	 * @vxdoc directive
	 * @name vx.directive:vBindHtml
	 *
	 * @description
	 * Creates a binding that will innerHTML the result of evaluating the `expression` into the current
	 * element. *The innerHTML-ed content will not be sanitized!* You should use this directive only if
	 * {@link vSanitize.directive:vBindHtml vBindHtml} directive is too
	 * restrictive and when you absolutely trust the source of the content you are binding to.
	 *
	 * See {@link vSanitize.$sanitize $sanitize} docs for examples.
	 *
	 * @element ANY
	 * @param {expression} vBindHtml {@link guide/expression Expression} to evaluate.
	 */
	/*
	function vBindHtmlDirective() {
		return function(scope, element, attr) {
			element.addClass('v-binding').data('$binding', attr.vBindHtml);
			scope.$watch(attr.vBindHtml, function vBindHtmlWatchAction(value) {
				element.html(value || '');
			});
		};
	}
	*/

	/**
	 * @vxdoc directive
	 * @name vx.directive:vBindTemplate
	 *
	 * @description
	 * The `vBindTemplate` directive specifies that the element
	 * text should be replaced with the template in vBindTemplate.
	 * Unlike vBind the vBindTemplate can contain multiple `{{` `}}`
	 * expressions. (This is required since some HTML elements
	 * can not have SPAN elements such as TITLE, or OPTION to name a few.)
	 *
	 * @element ANY
	 * @param {string} vBindTemplate template of form
	 *   <tt>{{</tt> <tt>expression</tt> <tt>}}</tt> to eval.
	 *
	 * @example
	 * Try it here: enter text in text box and watch the greeting change.
	 <doc:example>
	 <doc:source>
	 <script>
	 function Ctrl($scope) {
	 $scope.salutation = 'Hello';
	 $scope.name = 'World';
	 }
	 </script>
	 <div v-controller="Ctrl">
	 Salutation: <input type="text" v-model="salutation"><br>
	 Name: <input type="text" v-model="name"><br>
	 <pre v-bind-template="{{salutation}} {{name}}!"></pre>
	 </div>
	 </doc:source>
	 <doc:scenario>
	 it('should check v-bind', function() {
	 expect(using('.doc-example-live').binding('salutation')).
	 toBe('Hello');
	 expect(using('.doc-example-live').binding('name')).
	 toBe('World');
	 using('.doc-example-live').input('salutation').enter('Greetings');
	 using('.doc-example-live').input('name').enter('user');
	 expect(using('.doc-example-live').binding('salutation')).
	 toBe('Greetings');
	 expect(using('.doc-example-live').binding('name')).
	 toBe('user');
	 });
	 </doc:scenario>
	 </doc:example>
	 */
	/*
	vBindTemplateDirective.$inject = ['$interpolate'];
	function vBindTemplateDirective($interpolate) {
		return function(scope, element, attr) {
			// TODO: move this to scenario runner
			var interpolateFn = $interpolate(element.attr(attr.$attr.vBindTemplate));
			element.addClass('v-binding').data('$binding', interpolateFn);
			attr.$observe('vBindTemplate', function(value) {
				element.text(value);
			});
		};
	}
	*/

	/**
	 * @vxdoc directive
	 * @name vx.directive:vClick
	 *
	 * @description
	 * The vClick allows you to specify custom behavior when
	 * element is clicked.
	 *
	 * @element ANY
	 * @param {expression} vClick {@link guide/expression Expression} to evaluate upon
	 * click. (Event object is available as `$event`)
	 *
	 * @example
	 <doc:example>
	 <doc:source>
	 <button v-click="count = count + 1" v-init="count=0">
	 Increment
	 </button>
	 count: {{count}}
	 </doc:source>
	 <doc:scenario>
	 it('should check v-click', function() {
	 expect(binding('count')).toBe('0');
	 element('.doc-example-live :button').click();
	 expect(binding('count')).toBe('1');
	 });
	 </doc:scenario>
	 </doc:example>
	 */
	/**
	 * @vxdoc directive
	 * @name vx.directive:vDblclick
	 *
	 * @description
	 * The `vDblclick` directive allows you to specify custom behavior on dblclick event.
	 *
	 * @element ANY
	 * @param {expression} vDblclick {@link guide/expression Expression} to evaluate upon
	 * dblclick. (Event object is available as `$event`)
	 *
	 * @example
	 * See {@link vx.directive:vClick vClick}
	 */

	/**
	 * @vxdoc directive
	 * @name vx.directive:vMousedown
	 *
	 * @description
	 * The vMousedown directive allows you to specify custom behavior on mousedown event.
	 *
	 * @element ANY
	 * @param {expression} vMousedown {@link guide/expression Expression} to evaluate upon
	 * mousedown. (Event object is available as `$event`)
	 *
	 * @example
	 * See {@link vx.directive:vClick vClick}
	 */

	/**
	 * @vxdoc directive
	 * @name vx.directive:vMouseup
	 *
	 * @description
	 * Specify custom behavior on mouseup event.
	 *
	 * @element ANY
	 * @param {expression} vMouseup {@link guide/expression Expression} to evaluate upon
	 * mouseup. (Event object is available as `$event`)
	 *
	 * @example
	 * See {@link vx.directive:vClick vClick}
	 */

	/**
	 * @vxdoc directive
	 * @name vx.directive:vMouseover
	 *
	 * @description
	 * Specify custom behavior on mouseover event.
	 *
	 * @element ANY
	 * @param {expression} vMouseover {@link guide/expression Expression} to evaluate upon
	 * mouseover. (Event object is available as `$event`)
	 *
	 * @example
	 * See {@link vx.directive:vClick vClick}
	 */

	/**
	 * @vxdoc directive
	 * @name vx.directive:vMouseenter
	 *
	 * @description
	 * Specify custom behavior on mouseenter event.
	 *
	 * @element ANY
	 * @param {expression} vMouseenter {@link guide/expression Expression} to evaluate upon
	 * mouseenter. (Event object is available as `$event`)
	 *
	 * @example
	 * See {@link vx.directive:vClick vClick}
	 */

	/**
	 * @vxdoc directive
	 * @name vx.directive:vMouseleave
	 *
	 * @description
	 * Specify custom behavior on mouseleave event.
	 *
	 * @element ANY
	 * @param {expression} vMouseleave {@link guide/expression Expression} to evaluate upon
	 * mouseleave. (Event object is available as `$event`)
	 *
	 * @example
	 * See {@link vx.directive:vClick vClick}
	 */

	/**
	 * @vxdoc directive
	 * @name vx.directive:vMousemove
	 *
	 * @description
	 * Specify custom behavior on mousemove event.
	 *
	 * @element ANY
	 * @param {expression} vMousemove {@link guide/expression Expression} to evaluate upon
	 * mousemove. (Event object is available as `$event`)
	 *
	 * @example
	 * See {@link vx.directive:vClick vClick}
	 */

	/**
	 * @vxdoc directive
	 * @name v.directive:vKeydown
	 *
	 * @description
	 * Specify custom behavior on keydown event.
	 *
	 * @element ANY
	 * @param {expression} vKeydown {@link guide/expression Expression} to evaluate upon
	 * keydown. (Event object is available as `$event` and can be interrogated for keyCode, altKey, etc.)
	 *
	 * @example
	 * See {@link v.directive:vClick vClick}
	 */

	/**
	 * @vxdoc directive
	 * @name v.directive:vKeyup
	 *
	 * @description
	 * Specify custom behavior on keyup event.
	 *
	 * @element ANY
	 * @param {expression} vKeyup {@link guide/expression Expression} to evaluate upon
	 * keyup. (Event object is available as `$event` and can be interrogated for keyCode, altKey, etc.)
	 *
	 * @example
	 * See {@link v.directive:vClick vClick}
	 */

	var EVENTS = 'click dblclick mousedown mouseup mouseover mouseout mousemove mouseenter mouseleave keydown keyup keypress';
	var vEventDirectives = {};
	forEach((EVENTS).split(' '), function(name) {
		var directiveName = directiveNormalize('v-' + name);
		vEventDirectives[directiveName] = ['$parse', '$$remote', '$browser',
		function($parse, $$remote, $browser) {
			return function(scope, element, attr) {
				var fn = $parse(attr[directiveName]), eventName = lowercase(name);
				var await = attr.await ? int(attr.await) : 0;
				var eventhandler = function(event) {
					scope.$apply(function() {
						fn(scope, injectRemote(element, {
							$event : event
						}, attr[directiveName], false, $$remote));
					}, directiveName);
				};
				if (await)
					eventhandler = $browser.debounce(eventhandler, await);
				element.bind(eventName, function handler(event) {
					var target = event.target;
					//XXX maybe need more justify it ???
					if (target !== element[0]) {// process Propagated event
						var tname = _nodeName(target);
						// skip input elements bubbles
						if (tname === 'INPUT' || tname === 'TEXTAREA' || tname === 'BUTTON' || tname === 'SELECT' || tname === 'OPTION')
							return;
					}

					eventhandler(event);

					//TODO: how to deal with $locationProvider's $document.bind('click', function(event)...)
					// in Chrome 7.0.xxxx.0, click in form lead reload
					var nn = _nodeName(element);
					if (nn == 'A') {
						//event.stopPropagation();
						event.preventDefault();
					}
				});
			};
		}];

	});
	/**
	 * @vxdoc directive
	 * @name vx.directive:vSubmit
	 *
	 * @description
	 * Enables binding vx expressions to onsubmit events.
	 *
	 * Additionally it prevents the default action (which for form means sending the request to the
	 * server and reloading the current page).
	 *
	 * @element form
	 * @param {expression} vSubmit {@link guide/expression Expression} to eval.
	 *
	 * @example
	 <doc:example>
	 <doc:source>
	 <script>
	 function Ctrl($scope) {
	 $scope.list = [];
	 $scope.text = 'hello';
	 $scope.submit = function() {
	 if (this.text) {
	 this.list.push(this.text);
	 this.text = '';
	 }
	 };
	 }
	 </script>
	 <form v-submit="submit()" v-controller="Ctrl">
	 Enter text and hit enter:
	 <input type="text" v-model="text" name="text" />
	 <input type="submit" id="submit" value="Submit" />
	 <pre>list={{list}}</pre>
	 </form>
	 </doc:source>
	 <doc:scenario>
	 it('should check v-submit', function() {
	 expect(binding('list')).toBe('[]');
	 element('.doc-example-live #submit').click();
	 expect(binding('list')).toBe('["hello"]');
	 expect(input('text').val()).toBe('');
	 });
	 it('should ignore empty strings', function() {
	 expect(binding('list')).toBe('[]');
	 element('.doc-example-live #submit').click();
	 element('.doc-example-live #submit').click();
	 expect(binding('list')).toBe('["hello"]');
	 });
	 </doc:scenario>
	 </doc:example>
	 */
	vSubmitDirective.$inject = ['$parse', '$$remote'];
	function vSubmitDirective($parse, $$remote) {
		return {
			require : 'form',
			link : function(scope, element, attrs, ctrl) {
				var fn = $parse(attrs.vSubmit), parent = attrs.parent === 'true';
				element.bind('submit', function(event) {
					var formCtrl = ctrl;
					// forbid cascade submit
					if (event.target !== element[0]) {
						var formCtrl0 = jqLite(event.target).controller('form');
						if (formCtrl !== formCtrl0)
							return;
					}
					if (!formCtrl.$getError(parent)) {
						//scope.$apply(function() {
						fn(scope, injectRemote(element, {
							$event : event,
							$data : formCtrl.$getData(parent)
						}, attrs.vSubmit, true, $$remote));
						//}, 'v-submit');
					}
					//event.stopPropagation();
					event.preventDefault();
				});
			}
		};

	}

	/**
	 * class helper method
	 */
	function classDirective(name, selector) {
		name = 'vClass' + name;
		return function() {
			return {
				restrict : 'AC',
				link : linker
			};
		};
		function linker(scope, element, attr) {
			var oldVal;
			scope.$watch(attr[name], vClassWatchAction, true);
			attr.$observe('class', function(value) {
				var vClass = scope.$eval(attr[name]);
				vClassWatchAction(vClass, vClass);
			});
			if (name !== 'vClass') {
				scope.$watch('$index', function($index, old$index) {
					var mod = $index % 2;
					if (mod !== old$index % 2) {
						if (mod === selector) {
							addClass(scope.$eval(attr[name]));
						} else {
							removeClass(scope.$eval(attr[name]));
						}
					}
				});
			}

			function vClassWatchAction(newVal, oldVal) {
				if (selector === true || scope.$index % 2 === selector) {
					if (oldVal && !equals(newVal, oldVal)) {
						removeClass(oldVal);
					}
					addClass(newVal);
				}
				oldVal = copy(newVal);
			}

			function removeClass(classVal) {
				if (isObject(classVal) && !isArray(classVal)) {
					classVal = map(classVal, function(v, k) {
						if (v)
							return k;
					});
				}
				element.removeClass(isArray(classVal) ? classVal.join(' ') : classVal);
			}

			function addClass(classVal) {
				if (isObject(classVal) && !isArray(classVal)) {
					classVal = map(classVal, function(v, k) {
						if (v)
							return k;
					});
				}
				if (classVal) {
					element.addClass(isArray(classVal) ? classVal.join(' ') : classVal);
				}
			}

		}

	}

	/**
	 * @vxdoc directive
	 * @name vx.directive:vClass
	 *
	 * @description
	 * The `vClass` allows you to set CSS class on HTML element dynamically by databinding an
	 * expression that represents all classes to be added.
	 *
	 * The directive won't add duplicate classes if a particular class was already set.
	 *
	 * When the expression changes, the previously added classes are removed and only then the
	 * new classes are added.
	 *
	 * @element ANY
	 * @param {expression} vClass {@link guide/expression Expression} to eval. The result
	 *   of the evaluation can be a string representing space delimited class
	 *   names, an array, or a map of class names to boolean values.
	 *
	 * @example
	 <example>
	 <file name="index.html">
	 <input type="button" value="set" v-click="myVar='my-class'">
	 <input type="button" value="clear" v-click="myVar=''">
	 <br>
	 <span v-class="myVar">Sample Text</span>
	 </file>
	 <file name="style.css">
	 .my-class {
	 color: red;
	 }
	 </file>
	 <file name="scenario.js">
	 it('should check v-class', function() {
	 expect(element('.doc-example-live span').prop('className')).not().
	 toMatch(/my-class/);

	 using('.doc-example-live').element(':button:first').click();

	 expect(element('.doc-example-live span').prop('className')).
	 toMatch(/my-class/);

	 using('.doc-example-live').element(':button:last').click();

	 expect(element('.doc-example-live span').prop('className')).not().
	 toMatch(/my-class/);
	 });
	 </file>
	 </example>
	 */
	//var vClassDirective = classDirective('', true);

	/**
	 * @vxdoc directive
	 * @name vx.directive:vClassOdd
	 *
	 * @description
	 * The `vClassOdd` and `vClassEven` directives work exactly as
	 * {@link vx.directive:vClass vClass}, except it works in
	 * conjunction with `vRepeat` and takes affect only on odd (even) rows.
	 *
	 * This directive can be applied only within a scope of an
	 * {@link vx.directive:vRepeat vRepeat}.
	 *
	 * @element ANY
	 * @param {expression} vClassOdd {@link guide/expression Expression} to eval. The result
	 *   of the evaluation can be a string representing space delimited class names or an array.
	 *
	 * @example
	 <example>
	 <file name="index.html">
	 <ol v-init="names=['John', 'Mary', 'Cate', 'Suz']">
	 <li v-repeat="name in names">
	 <span v-class-odd="'odd'" v-class-even="'even'">
	 {{name}}
	 </span>
	 </li>
	 </ol>
	 </file>
	 <file name="style.css">
	 .odd {
	 color: red;
	 }
	 .even {
	 color: blue;
	 }
	 </file>
	 <file name="scenario.js">
	 it('should check v-class-odd and v-class-even', function() {
	 expect(element('.doc-example-live li:first span').prop('className')).
	 toMatch(/odd/);
	 expect(element('.doc-example-live li:last span').prop('className')).
	 toMatch(/even/);
	 });
	 </file>
	 </example>
	 */
	//var vClassOddDirective = classDirective('Odd', 0);

	/**
	 * @vxdoc directive
	 * @name vx.directive:vClassEven
	 *
	 * @description
	 * The `vClassOdd` and `vClassEven` directives work exactly as
	 * {@link vx.directive:vClass vClass}, except it works in
	 * conjunction with `vRepeat` and takes affect only on odd (even) rows.
	 *
	 * This directive can be applied only within a scope of an
	 * {@link vx.directive:vRepeat vRepeat}.
	 *
	 * @element ANY
	 * @param {expression} vClassEven {@link guide/expression Expression} to eval. The
	 *   result of the evaluation can be a string representing space delimited class names or an array.
	 *
	 * @example
	 <example>
	 <file name="index.html">
	 <ol v-init="names=['John', 'Mary', 'Cate', 'Suz']">
	 <li v-repeat="name in names">
	 <span v-class-odd="'odd'" v-class-even="'even'">
	 {{name}} &nbsp; &nbsp; &nbsp;
	 </span>
	 </li>
	 </ol>
	 </file>
	 <file name="style.css">
	 .odd {
	 color: red;
	 }
	 .even {
	 color: blue;
	 }
	 </file>
	 <file name="scenario.js">
	 it('should check v-class-odd and v-class-even', function() {
	 expect(element('.doc-example-live li:first span').prop('className')).
	 toMatch(/odd/);
	 expect(element('.doc-example-live li:last span').prop('className')).
	 toMatch(/even/);
	 });
	 </file>
	 </example>
	 */
	//var vClassEvenDirective = classDirective('Even', 1);

	/**
	 * @vxdoc directive
	 * @name vx.directive:vShow
	 *
	 * @description
	 * The `vShow` and `vHide` directives show or hide a portion of the DOM tree (HTML)
	 * conditionally based on **"truthy"** values evaluated within an {expression}. In other
	 * words, if the expression assigned to **vShow evaluates to a true value** then **the element is set to visible**
	 * (via `display:block` in css) and **if false** then **the element is set to hidden** (so display:none).
	 * With vHide this is the reverse whereas true values cause the element itself to become
	 * hidden.
	 *
	 * Additionally, you can also provide animations via the vAnimate attribute to animate the **show**
	 * and **hide** effects.
	 *
	 * @animations
	 * show - happens after the vShow expression evaluates to a truthy value and the contents are set to visible
	 * hide - happens before the vShow expression evaluates to a non truthy value and just before the contents are set to hidden

	 *
	 * @element ANY
	 * @param {expression} vShow If the {@link guide/expression expression} is truthy
	 *     then the element is shown or hidden respectively.
	 *
	 * @example
	 <example animations="true">
	 <file name="index.html">
	 Click me: <input type="checkbox" v-model="checked"><br/>
	 <div>
	 Show:
	 <span class="check-element"
	 v-show="checked"
	 v-animate="{show: 'example-show', hide: 'example-hide'}">
	 <span class="icon-thumbs-up"></span> I show up when your checkbox is checked.
	 </span>
	 </div>
	 <div>
	 Hide:
	 <span class="check-element"
	 v-hide="checked"
	 v-animate="{show: 'example-show', hide: 'example-hide'}">
	 <span class="icon-thumbs-down"></span> I hide when your checkbox is checked.
	 </span>
	 </div>
	 </file>
	 <file name="animations.css">
	 .example-show, .example-hide {
	 -webkit-transition:all linear 0.5s;
	 -moz-transition:all linear 0.5s;
	 -ms-transition:all linear 0.5s;
	 -o-transition:all linear 0.5s;
	 transition:all linear 0.5s;
	 }

	 .example-show {
	 line-height:0;
	 opacity:0;
	 padding:0 10px;
	 }
	 .example-show-active.example-show-active {
	 line-height:20px;
	 opacity:1;
	 padding:10px;
	 border:1px solid black;
	 background:white;
	 }

	 .example-hide {
	 line-height:20px;
	 opacity:1;
	 padding:10px;
	 border:1px solid black;
	 background:white;
	 }
	 .example-hide-active.example-hide-active {
	 line-height:0;
	 opacity:0;
	 padding:0 10px;
	 }

	 .check-element {
	 padding:10px;
	 border:1px solid black;
	 background:white;
	 }
	 </file>
	 <file name="scenario.js">
	 it('should check v-show / v-hide', function() {
	 expect(element('.doc-example-live span:first:hidden').count()).toEqual(1);
	 expect(element('.doc-example-live span:last:visible').count()).toEqual(1);

	 input('checked').check();

	 expect(element('.doc-example-live span:first:visible').count()).toEqual(1);
	 expect(element('.doc-example-live span:last:hidden').count()).toEqual(1);
	 });
	 </file>
	 </example>
	 */
	//TODO(misko): refactor to remove element from the DOM
	vShowDirective.$inject = ['$animator'];
	function vShowDirective($animator) {
		return {
			restrict : 'AC',
			link : function(scope, element, attr) {
				var animate = $animator(scope, attr);
				scope.$watch(attr.vShow, function vShowWatchAction(value) {
					animate[toBoolean(value) ? 'show' : 'hide'](element);
				});
			}
		};
	}

	/**
	 * @vxdoc directive
	 * @name vx.directive:vHide
	 *
	 * @description
	 * The `vHide` and `vShow` directives hide or show a portion of the DOM tree (HTML)
	 * conditionally based on **"truthy"** values evaluated within an {expression}. In other
	 * words, if the expression assigned to **vShow evaluates to a true value** then **the element is set to visible**
	 * (via `display:block` in css) and **if false** then **the element is set to hidden** (so display:none).
	 * With vHide this is the reverse whereas true values cause the element itself to become
	 * hidden.
	 *
	 * Additionally, you can also provide animations via the vAnimate attribute to animate the **show**
	 * and **hide** effects.
	 *
	 * @animations
	 * show - happens after the vHide expression evaluates to a non truthy value and the contents are set to visible
	 * hide - happens after the vHide expression evaluates to a truthy value and just before the contents are set to hidden
	 *
	 * @element ANY
	 * @param {expression} vHide If the {@link guide/expression expression} is truthy then
	 *     the element is shown or hidden respectively.
	 *
	 * @example
	 <example animations="true">
	 <file name="index.html">
	 Click me: <input type="checkbox" v-model="checked"><br/>
	 <div>
	 Show:
	 <span class="check-element"
	 v-show="checked"
	 v-animate="{show: 'example-show', hide: 'example-hide'}">
	 <span class="icon-thumbs-up"></span> I show up when your checkbox is checked.
	 </span>
	 </div>
	 <div>
	 Hide:
	 <span class="check-element"
	 v-hide="checked"
	 v-animate="{show: 'example-show', hide: 'example-hide'}">
	 <span class="icon-thumbs-down"></span> I hide when your checkbox is checked.
	 </span>
	 </div>
	 </file>
	 <file name="animations.css">
	 .example-show, .example-hide {
	 -webkit-transition:all linear 0.5s;
	 -moz-transition:all linear 0.5s;
	 -ms-transition:all linear 0.5s;
	 -o-transition:all linear 0.5s;
	 transition:all linear 0.5s;
	 }

	 .example-show {
	 line-height:0;
	 opacity:0;
	 padding:0 10px;
	 }
	 .example-show-active.example-show-active {
	 line-height:20px;
	 opacity:1;
	 padding:10px;
	 border:1px solid black;
	 background:white;
	 }

	 .example-hide {
	 line-height:20px;
	 opacity:1;
	 padding:10px;
	 border:1px solid black;
	 background:white;
	 }
	 .example-hide-active.example-hide-active {
	 line-height:0;
	 opacity:0;
	 padding:0 10px;
	 }

	 .check-element {
	 padding:10px;
	 border:1px solid black;
	 background:white;
	 }
	 </file>
	 <file name="scenario.js">
	 it('should check v-show / v-hide', function() {
	 expect(element('.doc-example-live .check-element:first:hidden').count()).toEqual(1);
	 expect(element('.doc-example-live .check-element:last:visible').count()).toEqual(1);

	 input('checked').check();

	 expect(element('.doc-example-live .check-element:first:visible').count()).toEqual(1);
	 expect(element('.doc-example-live .check-element:last:hidden').count()).toEqual(1);
	 });
	 </file>
	 </example>
	 */
	//TODO(misko): refactor to remove element from the DOM
	vHideDirective.$inject = ['$animator'];
	function vHideDirective($animator) {
		return {
			restrict : 'AC',
			link : function(scope, element, attr) {
				var animate = $animator(scope, attr);
				scope.$watch(attr.vHide, function vHideWatchAction(value) {
					animate[toBoolean(value) ? 'hide' : 'show'](element);
				});
			}
		};
	}

	/**
	 * @vxdoc directive
	 * @name vx.directive:vStyle
	 *
	 * @description
	 * The `vStyle` directive allows you to set CSS style on an HTML element conditionally.
	 *
	 * @element ANY
	 * @param {expression} vStyle {@link guide/expression Expression} which evals to an
	 *      object whose keys are CSS style names and values are corresponding values for those CSS
	 *      keys.
	 *
	 * @example
	 <example>
	 <file name="index.html">
	 <input type="button" value="set" v-click="myStyle={color:'red'}">
	 <input type="button" value="clear" v-click="myStyle={}">
	 <br/>
	 <span v-style="myStyle">Sample Text</span>
	 <pre>myStyle={{myStyle}}</pre>
	 </file>
	 <file name="style.css">
	 span {
	 color: black;
	 }
	 </file>
	 <file name="scenario.js">
	 it('should check v-style', function() {
	 expect(element('.doc-example-live span').css('color')).toBe('rgb(0, 0, 0)');
	 element('.doc-example-live :button[value=set]').click();
	 expect(element('.doc-example-live span').css('color')).toBe('rgb(255, 0, 0)');
	 element('.doc-example-live :button[value=clear]').click();
	 expect(element('.doc-example-live span').css('color')).toBe('rgb(0, 0, 0)');
	 });
	 </file>
	 </example>
	 */
	/*
	function vStyleDirective() {
		return {
			restrict : 'AC',
			link : function(scope, element, attr) {
				scope.$watch(attr.vStyle, function vStyleWatchAction(newStyles, oldStyles) {
					if (oldStyles && (newStyles !== oldStyles)) {
						forEach(oldStyles, function(val, style) {
							element.css(style, '');
						});
					}
					if (newStyles)
						element.css(newStyles);
				}, true);
			}
		};
	}
	*/

	/**
	 * @vxdoc directive
	 * @name vx.directive:vCloak
	 *
	 * @description
	 * The `vCloak` directive is used to prevent the VX html template from being briefly
	 * displayed by the browser in its raw (uncompiled) form while your application is loading. Use this
	 * directive to avoid the undesirable flicker effect caused by the html template display.
	 *
	 * The directive can be applied to the `<body>` element, but typically a fine-grained application is
	 * preferred in order to benefit from progressive rendering of the browser view.
	 *
	 * `vCloak` works in cooperation with a css rule that is embedded within `vx.js` and
	 *  `vx.min.js` files. Following is the css rule:
	 *
	 * <pre>
	 * [v\:cloak], [v-cloak], [data-v-cloak], [x-v-cloak], .v-cloak, .x-v-cloak {
	 *   display: none;
	 * }
	 * </pre>
	 *
	 * When this css rule is loaded by the browser, all html elements (including their children) that
	 * are tagged with the `v-cloak` directive are hidden. When VX comes across this directive
	 * during the compilation of the template it deletes the `vCloak` element attribute, which
	 * makes the compiled element visible.
	 *
	 * For the best result, `vx.js` script must be loaded in the head section of the html file;
	 * alternatively, the css rule (above) must be included in the external stylesheet of the
	 * application.
	 *
	 * Legacy browsers, like IE7, do not provide attribute selector support (added in CSS 2.1) so they
	 * cannot match the `[v\:cloak]` selector. To work around this limitation, you must add the css
	 * class `vCloak` in addition to `vCloak` directive as shown in the example below.
	 *
	 * @element ANY
	 *
	 * @example
	 <doc:example>
	 <doc:source>
	 <div id="template1" v-cloak>{{ 'hello' }}</div>
	 <div id="template2" v-cloak class="v-cloak">{{ 'hello IE7' }}</div>
	 </doc:source>
	 <doc:scenario>
	 it('should remove the template directive and css class', function() {
	 expect(element('.doc-example-live #template1').attr('v-cloak')).
	 not().toBeDefined();
	 expect(element('.doc-example-live #template2').attr('v-cloak')).
	 not().toBeDefined();
	 });
	 </doc:scenario>
	 </doc:example>
	 *
	 */
	/*
	function vCloakDirective() {
		return {
			restrict : 'AC',
			compile : function(element, attr) {
				attr.$set('vCloak', undefined);
				element.removeClass('v-cloak');
			}
		};
	}
	*/

	/**
	 * @vxdoc directive
	 * @name vx.directive:vDisabled
	 * @restrict A
	 *
	 * @description
	 *
	 * The following markup will make the button enabled on Chrome/Firefox but not on IE8 and older IEs:
	 * <pre>
	 * <div v-init="scope = { isDisabled: false }">
	 *  <button disabled="{{scope.isDisabled}}">Disabled</button>
	 * </div>
	 * </pre>
	 *
	 * The HTML specs do not require browsers to preserve the special attributes such as disabled.
	 * (The presence of them means true and absence means false)
	 * This prevents the vx compiler from correctly retrieving the binding expression.
	 * To solve this problem, we introduce the `vDisabled` directive.
	 *
	 * @example
	 <doc:example>
	 <doc:source>
	 Click me to toggle: <input type="checkbox" v-model="checked"><br/>
	 <button v-model="button" v-disabled="checked">Button</button>
	 </doc:source>
	 <doc:scenario>
	 it('should toggle button', function() {
	 expect(element('.doc-example-live :button').prop('disabled')).toBeFalsy();
	 input('checked').check();
	 expect(element('.doc-example-live :button').prop('disabled')).toBeTruthy();
	 });
	 </doc:scenario>
	 </doc:example>
	 *
	 * @element INPUT
	 * @param {expression} vDisabled VX expression that will be evaluated.
	 */

	/**
	 * @vxdoc directive
	 * @name vx.directive:vChecked
	 * @restrict A
	 *
	 * @description
	 * The HTML specs do not require browsers to preserve the special attributes such as checked.
	 * (The presence of them means true and absence means false)
	 * This prevents the vx compiler from correctly retrieving the binding expression.
	 * To solve this problem, we introduce the `vChecked` directive.
	 * @example
	 <doc:example>
	 <doc:source>
	 Check me to check both: <input type="checkbox" v-model="master"><br/>
	 <input id="checkSlave" type="checkbox" v-checked="master">
	 </doc:source>
	 <doc:scenario>
	 it('should check both checkBoxes', function() {
	 expect(element('.doc-example-live #checkSlave').prop('checked')).toBeFalsy();
	 input('master').check();
	 expect(element('.doc-example-live #checkSlave').prop('checked')).toBeTruthy();
	 });
	 </doc:scenario>
	 </doc:example>
	 *
	 * @element INPUT
	 * @param {expression} vChecked VX expression that will be evaluated.
	 */

	/**
	 * @vxdoc directive
	 * @name vx.directive:vMultiple
	 * @restrict A
	 *
	 * @description
	 * The HTML specs do not require browsers to preserve the special attributes such as multiple.
	 * (The presence of them means true and absence means false)
	 * This prevents the vx compiler from correctly retrieving the binding expression.
	 * To solve this problem, we introduce the `vMultiple` directive.
	 *
	 * @example
	 <doc:example>
	 <doc:source>
	 Check me check multiple: <input type="checkbox" v-model="checked"><br/>
	 <select id="select" v-multiple="checked">
	 <option>Misko</option>
	 <option>Igor</option>
	 <option>Vojta</option>
	 <option>Di</option>
	 </select>
	 </doc:source>
	 <doc:scenario>
	 it('should toggle multiple', function() {
	 expect(element('.doc-example-live #select').prop('multiple')).toBeFalsy();
	 input('checked').check();
	 expect(element('.doc-example-live #select').prop('multiple')).toBeTruthy();
	 });
	 </doc:scenario>
	 </doc:example>
	 *
	 * @element SELECT
	 * @param {expression} vMultiple VX expression that will be evaluated.
	 */

	/**
	 * @vxdoc directive
	 * @name vx.directive:vReadonly
	 * @restrict A
	 *
	 * @description
	 * The HTML specs do not require browsers to preserve the special attributes such as readonly.
	 * (The presence of them means true and absence means false)
	 * This prevents the vx compiler from correctly retrieving the binding expression.
	 * To solve this problem, we introduce the `vReadonly` directive.
	 * @example
	 <doc:example>
	 <doc:source>
	 Check me to make text readonly: <input type="checkbox" v-model="checked"><br/>
	 <input type="text" v-readonly="checked" value="I'm VX"/>
	 </doc:source>
	 <doc:scenario>
	 it('should toggle readonly attr', function() {
	 expect(element('.doc-example-live :text').prop('readonly')).toBeFalsy();
	 input('checked').check();
	 expect(element('.doc-example-live :text').prop('readonly')).toBeTruthy();
	 });
	 </doc:scenario>
	 </doc:example>
	 *
	 * @element INPUT
	 * @param {string} expression VX expression that will be evaluated.
	 */

	/**
	 * @vxdoc directive
	 * @name vx.directive:vSelected
	 * @restrict A
	 *
	 * @description
	 * The HTML specs do not require browsers to preserve the special attributes such as selected.
	 * (The presence of them means true and absence means false)
	 * This prevents the vx compiler from correctly retrieving the binding expression.
	 * To solve this problem, we introduced the `vSelected` directive.
	 * @example
	 <doc:example>
	 <doc:source>
	 Check me to select: <input type="checkbox" v-model="selected"><br/>
	 <select>
	 <option>Hello!</option>
	 <option id="greet" v-selected="selected">Greetings!</option>
	 </select>
	 </doc:source>
	 <doc:scenario>
	 it('should select Greetings!', function() {
	 expect(element('.doc-example-live #greet').prop('selected')).toBeFalsy();
	 input('selected').check();
	 expect(element('.doc-example-live #greet').prop('selected')).toBeTruthy();
	 });
	 </doc:scenario>
	 </doc:example>
	 *
	 * @element OPTION
	 * @param {string} expression VX expression that will be evaluated.
	 */

	/**
	 * @vxdoc directive
	 * @name v.directive:vOpen
	 * @restrict A
	 *
	 * @description
	 * The HTML specs do not require browsers to preserve the special attributes such as open.
	 * (The presence of them means true and absence means false)
	 * This prevents the vx compiler from correctly retrieving the binding expression.
	 * To solve this problem, we introduce the `vOpen` directive.
	 *
	 * @example
	 <doc:example>
	 <doc:source>
	 Check me check multiple: <input type="checkbox" v-model="open"><br/>
	 <details id="details" v-open="open">
	 <summary>Show/Hide me</summary>
	 </details>
	 </doc:source>
	 <doc:scenario>
	 it('should toggle open', function() {
	 expect(element('#details').prop('open')).toBeFalsy();
	 input('open').check();
	 expect(element('#details').prop('open')).toBeTruthy();
	 });
	 </doc:scenario>
	 </doc:example>
	 *
	 * @element DETAILS
	 * @param {string} expression VX expression that will be evaluated.
	 */
	var vAttributeAliasDirectives = {};

	// boolean attrs are evaluated
	forEach(BOOLEAN_ATTR, function(propName, attrName) {
		var normalized = directiveNormalize('v-' + attrName);
		vAttributeAliasDirectives[normalized] = function() {
			return {
				priority : 100,
				link : function(scope, element, attr) {
					scope.$watch(attr[normalized], function vBooleanAttrWatchAction(value) {
						attr.$set(attrName, !!value);
					});
				}
			};
		};
	});

	/**
	 * @vxdoc directive
	 * @name vx.directive:vHref
	 * @restrict A
	 *
	 * @description
	 * Using VX markup like {{hash}} in an href attribute makes
	 * the page open to a wrong URL, if the user clicks that link before
	 * vx has a chance to replace the {{hash}} with actual URL, the
	 * link will be broken and will most likely return a 404 error.
	 * The `vHref` directive solves this problem.
	 *
	 * The buggy way to write it:
	 * <pre>
	 * <a href="http://www.gravatar.com/avatar/{{hash}}"/>
	 * </pre>
	 *
	 * The correct way to write it:
	 * <pre>
	 * <a v-href="http://www.gravatar.com/avatar/{{hash}}"/>
	 * </pre>
	 *
	 * @element A
	 * @param {template} vHref any string which can contain `{{}}` markup.
	 *
	 * @example
	 * This example uses `link` variable inside `href` attribute:
	 <doc:example>
	 <doc:source>
	 <input v-model="value" /><br />
	 <a id="link-1" href v-click="value = 1">link 1</a> (link, don't reload)<br />
	 <a id="link-2" href="" v-click="value = 2">link 2</a> (link, don't reload)<br />
	 <a id="link-3" v-href="/{{'123'}}">link 3</a> (link, reload!)<br />
	 <a id="link-4" href="" name="xx" v-click="value = 4">anchor</a> (link, don't reload)<br />
	 <a id="link-5" name="xxx" v-click="value = 5">anchor</a> (no link)<br />
	 <a id="link-6" v-href="{{value}}">link</a> (link, change location)
	 </doc:source>
	 <doc:scenario>
	 it('should execute v-click but not reload when href without value', function() {
	 element('#link-1').click();
	 expect(input('value').val()).toEqual('1');
	 expect(element('#link-1').attr('href')).toBe("");
	 });

	 it('should execute v-click but not reload when href empty string', function() {
	 element('#link-2').click();
	 expect(input('value').val()).toEqual('2');
	 expect(element('#link-2').attr('href')).toBe("");
	 });

	 it('should execute v-click and change url when v-href specified', function() {
	 expect(element('#link-3').attr('href')).toBe("/123");

	 element('#link-3').click();
	 expect(browser().window().path()).toEqual('/123');
	 });

	 it('should execute v-click but not reload when href empty string and name specified', function() {
	 element('#link-4').click();
	 expect(input('value').val()).toEqual('4');
	 expect(element('#link-4').attr('href')).toBe('');
	 });

	 it('should execute v-click but not reload when no href but name specified', function() {
	 element('#link-5').click();
	 expect(input('value').val()).toEqual('5');
	 expect(element('#link-5').attr('href')).toBe(undefined);
	 });

	 it('should only change url when only v-href', function() {
	 input('value').enter('6');
	 expect(element('#link-6').attr('href')).toBe('6');

	 element('#link-6').click();
	 expect(browser().location().url()).toEqual('/6');
	 });
	 </doc:scenario>
	 </doc:example>
	 */

	/**
	 * @vxdoc directive
	 * @name vx.directive:vSrc
	 * @restrict A
	 *
	 * @description
	 * Using VX markup like `{{hash}}` in a `src` attribute doesn't
	 * work right: The browser will fetch from the URL with the literal
	 * text `{{hash}}` until VX replaces the expression inside
	 * `{{hash}}`. The `vSrc` directive solves this problem.
	 *
	 * The buggy way to write it:
	 * <pre>
	 * <img src="http://www.gravatar.com/avatar/{{hash}}"/>
	 * </pre>
	 *
	 * The correct way to write it:
	 * <pre>
	 * <img v-src="http://www.gravatar.com/avatar/{{hash}}"/>
	 * </pre>
	 *
	 * @element IMG
	 * @param {template} vSrc any string which can contain `{{}}` markup.
	 */
	/**
	 * @vxdoc directive
	 * @name vx.directive:vSrcset
	 * @restrict A
	 *
	 * @description
	 * Using vx markup like `{{hash}}` in a `srcset` attribute doesn't
	 * work right: The browser will fetch from the URL with the literal
	 * text `{{hash}}` until vx replaces the expression inside
	 * `{{hash}}`. The `vSrcset` directive solves this problem.
	 *
	 * The buggy way to write it:
	 * <pre>
	 * <img srcset="http://www.gravatar.com/avatar/{{hash}} 2x"/>
	 * </pre>
	 *
	 * The correct way to write it:
	 * <pre>
	 * <img v-srcset="http://www.gravatar.com/avatar/{{hash}} 2x"/>
	 * </pre>
	 *
	 * @element IMG
	 * @param {template} vSrcset any string which can contain `{{}}` markup.
	 */
	// v-src, v-srcset, v-href are interpolated
	forEach(['src', 'srcset', 'href'], function(attrName) {
		var normalized = directiveNormalize('v-' + attrName);
		vAttributeAliasDirectives[normalized] = function() {
			return {
				priority : 99, // it needs to run after the attributes are interpolated
				link : function(scope, element, attr) {
					attr.$observe(normalized, function(value) {
						if (!value)
							return;
						attr.$set(attrName, value);

						// on IE, if "v:src" directive declaration is used and "src" attribute doesn't exist
						// then calling element.setAttribute('src', 'foo') doesn't do anything, so we need
						// to set the property as well to achieve the desired effect.
						// we use attr[attrName] value since $set can sanitize the url.
						if (msie)
							element.prop(attrName, attr[attrName]);
					});
				}
			};
		};
	});

	/**
	 * @vxdoc directive
	 * @name vx.directive:vTransclude
	 *
	 * @description
	 * Insert the transcluded DOM here.
	 *
	 * @element ANY
	 *
	 * @example
	 <doc:example module="transclude">
	 <doc:source>
	 <script>
	 function Ctrl($scope) {
	 $scope.title = 'Lorem Ipsum';
	 $scope.text = 'Neque porro quisquam est qui dolorem ipsum quia dolor...';
	 }

	 vx.module('transclude', [])
	 .directive('pane', function(){
	 return {
	 restrict: 'E',
	 transclude: true,
	 scope: 'isolate',
	 locals: { title:'bind' },
	 template: '<div style="border: 1px solid black;">' +
	 '<div style="background-color: gray">{{title}}</div>' +
	 '<div v-transclude></div>' +
	 '</div>'
	 };
	 });
	 </script>
	 <div v-controller="Ctrl">
	 <input v-model="title"><br>
	 <textarea v-model="text"></textarea> <br/>
	 <pane title="{{title}}">{{text}}</pane>
	 </div>
	 </doc:source>
	 <doc:scenario>
	 it('should have transcluded', function() {
	 input('title').enter('TITLE');
	 input('text').enter('TEXT');
	 expect(binding('title')).toEqual('TITLE');
	 expect(binding('text')).toEqual('TEXT');
	 });
	 </doc:scenario>
	 </doc:example>
	 *
	 */
	/*
	function vTranscludeDirective() {
		return {
			restrict : 'AC',
			controller : ['$transclude', '$element',
			function($transclude, $element) {
				$transclude(function(clone) {
					$element.append(clone);
				});
			}]

		};
	}
	*/
	/*
	function styleDirective() {
		return {
			restrict : 'E',
			terminal : true
		};
	}
	*/

	/**
	 * @vxdoc directive
	 * @name vx.directive:vInclude
	 * @restrict ECA
	 *
	 * @description
	 * Fetches, compiles and includes an external HTML fragment.
	 *
	 * Keep in mind that Same Origin Policy applies to included resources
	 * (e.g. vInclude won't work for cross-domain requests on all browsers and for
	 *  file:// access on some browsers).
	 *
	 * Additionally, you can also provide animations via the vAnimate attribute to animate the **enter**
	 * and **leave** effects.
	 *
	 * @animations
	 * enter - happens just after the vInclude contents change and a new DOM element is created and injected into the vInclude container
	 * leave - happens just after the vInclude contents change and just before the former contents are removed from the DOM
	 *
	 * @scope
	 *
	 * @param {string} vInclude|src vx expression evaluating to URL. If the source is a string constant,
	 *                 make sure you wrap it in quotes, e.g. `src="'myPartialTemplate.html'"`.
	 * @param {string=} onload Expression to evaluate when a new partial is loaded.
	 *
	 * @param {string=} autoscroll Whether `vInclude` should call {@link vx.$anchorScroll
	 *                  $anchorScroll} to scroll the viewport after the content is loaded.
	 *
	 *                  - If the attribute is not set, disable scrolling.
	 *                  - If the attribute is set without value, enable scrolling.
	 *                  - Otherwise enable scrolling only if the expression evaluates to truthy value.
	 *
	 * @example
	 <example animations="true">
	 <file name="index.html">
	 <div v-controller="Ctrl">
	 <select v-model="template" v-options="t.name for t in templates">
	 <option value="">(blank)</option>
	 </select>
	 url of the template: <tt>{{template.url}}</tt>
	 <hr/>
	 <div class="example-animate-container"
	 v-include="template.url"
	 v-animate="{enter: 'example-enter', leave: 'example-leave'}"></div>
	 </div>
	 </file>
	 <file name="script.js">
	 function Ctrl($scope) {
	 $scope.templates =
	 [ { name: 'template1.html', url: 'template1.html'}
	 , { name: 'template2.html', url: 'template2.html'} ];
	 $scope.template = $scope.templates[0];
	 }
	 </file>
	 <file name="template1.html">
	 <div>Content of template1.html</div>
	 </file>
	 <file name="template2.html">
	 <div>Content of template2.html</div>
	 <file name="animations.css">
	 .example-leave,
	 .example-enter {
	 -webkit-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
	 -moz-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
	 -ms-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
	 -o-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
	 transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
	 position:absolute;
	 top:0;
	 left:0;
	 right:0;
	 bottom:0;
	 }
	 .example-animate-container > * {
	 display:block;
	 padding:10px;
	 }
	 .example-enter {
	 top:-50px;
	 }
	 .example-enter.example-enter-active {
	 top:0;
	 }
	 .example-leave {
	 top:0;
	 }
	 .example-leave.example-leave-active {
	 top:50px;
	 }
	 /file>
	 <file name="scenario.js">
	 it('should load template1.html', function() {
	 expect(element('.doc-example-live [v-include]').text()).
	 toMatch(/Content of template1.html/);
	 });
	 it('should load template2.html', function() {
	 select('template').option('1');
	 expect(element('.doc-example-live [v-include]').text()).
	 toMatch(/Content of template2.html/);
	 });
	 it('should change to blank', function() {
	 select('template').option('');
	 expect(element('.doc-example-live [v-include]').text()).toEqual('');
	 });
	 </file>
	 </example>
	 */

	/**
	 * @vxdoc event
	 * @name vx.directive:vInclude#$includeContentRequested
	 * @eventOf vx.directive:vInclude
	 * @eventType emit on the scope vInclude was declared in
	 * @description
	 * Emitted every time the vInclude content is requested.
	 */

	/**
	 * @vxdoc event
	 * @name vx.directive:vInclude#$includeContentLoaded
	 * @eventOf vx.directive:vInclude
	 * @eventType emit on the current vInclude scope
	 * @description
	 * Emitted every time the vInclude content is reloaded.
	 */
	vIncludeDirective.$inject = ['$http', '$templateCache', '$compile', '$animator'];
	function vIncludeDirective($http, $templateCache, $compile, $animator) {
		return {
			restrict : 'ECA',
			terminal : true,
			compile : function(element, attr) {
				var srcExp = attr.vInclude || attr.src, onloadExp = attr.onload || '';
				return function(scope, element, attr) {
					var animate = $animator(scope, attr);
					var changeCounter = 0, childScope;
					var clearContent = function() {
						if (childScope) {
							childScope.$destroy();
							childScope = null;
						}
						//element.html('');
						animate.leave(element.contents(), element);
					};

					scope.$watch(srcExp, function vIncludeWatchAction(src) {
						var thisChangeId = ++changeCounter;
						if (src) {
							//XXX need $scope and ajaxPort???
							$http.get(src, {
								cache : $templateCache
							}).success(function(response) {
								if (thisChangeId !== changeCounter)
									return;
								if (childScope)
									childScope.$destroy();
								childScope = scope.$new();

								animate.leave(element.contents(), element);
								var contents = jqLite('<div/>').html(response).contents();
								animate.enter(contents, element);

								$compile(element.contents())(childScope);

								childScope.$emit('$includeContentLoaded');
								scope.$eval(onloadExp);
							}).error(function() {
								if (thisChangeId === changeCounter)
									clearContent();
							});
							scope.$emit('$includeContentRequested');
						} else {
							clearContent();
						}
					});
				};
			}
		};
	}

	var vViewControllers = viewControllers();

	function viewControllers() {
		var $httpBackend = null;

		function getTransition(scope, attrs, $targets, $animator) {
			var vAnimateAttr = attrs.vAnimate;
			if (vAnimateAttr) {
				var animate = $animator(scope, attrs);
				return function(newEl, oldEl, remove, back) {
					if (newEl && newEl.length) {
						if (oldEl && oldEl.length) {
							if (remove)
								animate.leave(oldEl, oldEl.parent(), null, back);
							else
								animate.hide(oldEl, oldEl.parent(), null, back);
						}
						animate.show(newEl, newEl.parent(), null, back);
					}
				};
			}
			return $targets.transition(attrs.vTransition);
		}


		vViewportController.$inject = ['$scope', '$element', '$attrs', '$targets', '$http', '$templateCache', '$compile', '$log', '$httpBackend', '$$remote', '$animator'];
		function vViewportController(scope, element, attr, $targets, $http, $templateCache, $compile, $log, httpBackend, $$remote, $animator) {
			$httpBackend = httpBackend;

			/*jshint validthis:true*/
			var view = this, pages = {
				activePage : null,
				activeIndex : 0,
				activeMax : 0,
				track : []
			}, subviews = [];
			var vpId = attr.vViewport || attr.id, transition = getTransition(scope, attr, $targets, $animator), noHistory = attr.history !== 'true', //
			onloadExp = attr.onload || '', onbeforeloadExp = attr.onbeforeload || '';

			if (!vpId)
				throw vError(100, 'viewport must have id from "v-viewport" or "id" attribute');

			var parentView = element.parent().controller('vViewport');
			var childScope = scope.$new();
			scope.$$viewport = vpId;

			view.$id = vpId;
			view.$noHistory = noHistory;
			var applied = attr.apply === 'true';
			var ajaxPort = attr.ajaxPort;

			if (applied) {
				scope.$$applied = scope;
				scope.$repaint = repaintFactory(element);
			}
			if (ajaxPort)
				scope.$$ajaxPort = ajaxPort;

			view.$activeElement = jqLite(wrapInner(element[0], element.contents()));
			$compile(view.$activeElement)(childScope);

			view.$pages = pages;
			view.$subviews = subviews;

			scope.$Remoting = scope.$Submitting = 0;
			view.$$remoteTouch = function(submit) {
				scope.$Remoting++;
				if (submit)
					scope.$Submitting++;
			};

			view.$init = function() {
				if (parentView)
					parentView.$subviews.push(this);
				if ($targets.$viewports[view.$id])
					throw vError(101, 'duplicated viewport {0}', view.$id);
				$targets.$viewports[view.$id] = view;
				var target = attr.href;
				if (target)
					$targets(view.$id, target, view.$noHistory);
			};

			view.$destroy = function() {
				if (!view.$$destroyed) {
					$targets.clearTarget(view.$id);
					if (parentView)
						arrayRemove(parentView.$subviews, view);
					view.$clearSubviews();
					view.$clearPages();
					view.$activeElement = null;
					view.$$destroyed = true;
					childScope.$destroy();
					scope.$destroy();
				}
			};

			view.$clearSubviews = function() {
				for (var i = 0; i < subviews.length; i++) {
					var v = subviews[i];
					v.$destroy();
				}
			};

			view.$clearPages = function() {
				for (var i = 0; i < pages.track.length; i++) {
					var p = pages.track[i];
					p.$destroy();
				}
				pages.activeIndex = 0;
				pages.activeMax = 0;
				pages.track = [];
				pages.activePage = null;
			};

			view.$addPage = function(page) {
				pages.track.push(page);
				page.$index = pages.track.length;
			};

			view.$removePage = function(page) {
				arrayRemove(pages.track, page);
			};

			view.$trackPage = function(id, active) {
				var page, match = id.match(/^([\+\-]?)(\d+)$/), index, back;
				if (!match)
					throw vError(102, 'invalid page track, require [+-]number: {0}', id);
				index = int(id);
				if (match[1]) {// relative
					back = index < 0;
					if (pages.activeIndex < 1 || pages.track.length < 2)
						return;
					index = (pages.activeIndex + index - 1) % pages.track.length;
					if (index < 0)
						index += pages.track.length;
					index += 1;
					if (back && index > pages.activeIndex)
						index = 1;
					if (!back && index < pages.activeIndex)
						index = pages.track.length;
				} else {
					back = index < pages.activeIndex;
					if (index > pages.track.length)
						throw vError(103, 'page over max index: {0}', pages.track.length);
				}
				if (index === pages.activeIndex)
					return;
				if (!active && index > pages.activeMax)
					throw vError(104, 'page over max index: {0}', pages.activeMax);

				if (index === 0) {
					//XXX n === 0 is special, it means reset viewport (now just activeMax reset)
					if (!view.$reload)
						return;
					$log.debug('reload viewport "' + vpId + '"');
					return view.$reload();
				} else {
					pages.activeIndex = index;
					if (active)
						pages.activeMax = match[1] ? index : Math.max(index, pages.activeMax);
				}

				if (active) {
					$log.debug('viewport forward to page#' + index + ' in "' + vpId + '"');
				} else {
					$log.debug('viewport track to page#' + index + ' in "' + vpId + '"');
				}

				page = pages.track[index - 1];
				page.$load(back);
			};

			view.$load = function(newtarget, back) {
				var src = newtarget.url;
				if (onbeforeloadExp)
					src = scope.$eval(onbeforeloadExp) || newtarget.url;
				if (src) {
					view.$rootUrl = src;
					var base = getBase(src);
					view.$reload = function(back) {
						$http.get(src, {
							cache : $templateCache,
							$scope : scope
						}).success(function(response) {
							setInnerHTML(scope, element[0], response, function(newElement) {
								var oldEl = view.$activeElement;
								var el = view.$activeElement = jqLite(newElement);

								view.$clearPages();
								view.$clearSubviews();

								if (childScope)
									childScope.$destroy();

								childScope = scope.$new();
								$compile(el)(childScope);

								transition(oldEl, el, true, back);

								childScope.$root.$broadcast('$viewportContentLoaded', vpId, src);
								scope.$eval(onloadExp, injectRemote(element, null, onloadExp, false, $$remote));

								if (pages.track.length)
									view.$trackPage('1', true);

							}, base, false);
						}).error(function(reason, code, headers, config) {
							throw vError(105, 'http error [{0}] - {1}: {2}', code, reason, config.url);
						});
					};
					view.$reload(back);
				} else {
					throw vError(106, 'target url is null');
				}
			};

		}


		vPageController.$inject = ['$scope', '$element', '$attrs', '$http', '$templateCache', '$targets', '$compile', '$browser', '$httpBackend', '$$remote', '$animator'];
		function vPageController(scope, element, attr, $http, $templateCache, $targets, $compile, $browser, httpBackend, $$remote, $animator) {
			$httpBackend = httpBackend;

			/*jshint validthis:true*/
			var page = this, viewport = element.parent().controller('vViewport');
			var transition = getTransition(scope, attr, $targets, $animator), onloadExp = attr.onload, target = attr.href;
			var forms = [];

			if (!viewport)
				throw vError(107, 'v-page must inside v-viewport');

			element[0].style.display = 'none';
			if (!target)
				page.$$loaded = 'loaded';

			page.$element = element;

			page.$destroy = function() {
				page.$element = null;
				forms = [];
				viewport.$removePage(page);
			};

			page.$addForm = function(form) {
				forms.push(form);
			};

			page.$removeForm = function(form) {
				arrayRemove(forms, form);
			};

			page.$bind = function() {
				forEach(forms, function(f) {
					f.$bind();
				});
			};

			page.$unbind = function() {
				forEach(forms, function(f) {
					f.$unbind();
				});
			};

			page.$load = function(back) {
				if (target && !page.$$loaded) {
					var base = getBase(target);
					$http.get(target, {
						cache : $templateCache,
						$scope : scope
					}).success(function(response) {
						setInnerHTML(scope, element[0], response, function() {
							page.$$loaded = 'loaded';
							loadPage(page, back);
						}, base, true);
					}).error(function(reason, code, headers, config) {
						throw vError(108, 'http error [{0}] - {1}: {2}', code, reason, config.url);
					});
				} else {
					$browser.defer(function() {
						loadPage(page, back);
						scope.$apply(null, 'v-page');
					});
				}
			};

			/*
			 function loadPage(page, back) {
			 var el = clonePageElement(element);
			 element.after(el);
			 $compile(el.contents())(scope, null, false);
			 scope.$root.$broadcast('$pageContentLoaded', viewport.$id, page.$index, target);
			 scope.$eval(onloadExp);
			 transition(viewport.$pages.activePage.$element, el, true, back);
			 viewport.$pages.activePage = page;
			 }

			 function clonePageElement(el) {
			 var clone = jqLite(el[0].cloneNode(false)), children = el[0].childNodes;
			 for (var i = 0; i < children.length; i++) {
			 if (_nodeName(children[i]) !== 'SCRIPT')
			 clone.append(children[i].cloneNode(true));
			 }
			 return clone;
			 }
			 */

			function loadPage(page, back) {
				var el = element, lastPage = viewport.$pages.activePage;
				//XXX only compile once, otherwise memory-leak due to scope not $destroy
				if (lastPage)
					lastPage.$unbind();
				if (page.$$loaded !== 'compiled') {
					$compile(el.contents())(scope, null, false);
					page.$$loaded = 'compiled';
				} else {
					page.$bind();
				}

				scope.$root.$broadcast('$pageContentLoaded', viewport.$id, page.$index, target);
				scope.$eval(onloadExp, injectRemote(el, null, onloadExp, false, $$remote));
				transition(lastPage && lastPage.$element, el, false, back);
				viewport.$pages.activePage = page;
			}

		}

		return {
			viewport : vViewportController,
			page : vPageController
		};

		// -------------------- inner function ----------------------------
		function wrapInner(parent, children) {
			var div = document.createElement('div');
			div.className = 'viewport-wrapper';
			parent.appendChild(div);
			if (children) {
				for (var i = 0, ii = children.length; i < ii; i++) {
					div.appendChild(children[i]);
				}
			}
			return div;
		}

		// append HTML (include script)
		function setInnerHTML(scope, el, htmlCode, done, root, isPage) {
			el = isPage ? el : wrapInner(el);
			el.style.display = 'none';
			parseElements(htmlCode, el, scope, done, root);
		}

		function getBase(path) {
			var p = path && path.lastIndexOf('/');
			if (!p)
				return "";
			return path.substring(0, p + 1);
		}

		function getPath(src, root) {
			if (src.charAt(0) === '/')
				return src;
			return root + src;
		}

		function createElements(htmlCode) {
			//*** jimmy, for IE innerHTML will load script by src, so replace 'src=' to 'v-src='
			htmlCode = htmlCode.replace(/<script([^>]*)(src\s*=)([^>]*)>/gi, "<script$1v-src=$3>");
			var div = document.createElement('div');
			if (msie) {
				htmlCode = '<div style="display:none">for IE</div>' + htmlCode;
				div.innerHTML = htmlCode;
				div.removeChild(div.firstChild);
			} else {
				div.innerHTML = htmlCode;
			}
			var array = [], fc = div.firstChild;
			while (fc) {
				div.removeChild(fc);
				array.push(fc);
				fc = div.firstChild;
			}
			if (msie)
				IE_GC(div);
			return array;
		}

		function parseElements(htmlCode, el, scope, done, root) {
			var port = scope.$$ajaxPort;
			var nodes = createElements(htmlCode), node, remoteCount = 0, remoteSize = 0, i, ii;
			for ( i = 0, ii = nodes.length; i < ii; i++) {
				node = nodes[i];
				if (node.nodeName === 'SCRIPT' && node.getAttribute('v-src'))
					remoteSize++;
			}
			for ( i = 0; i < nodes.length; i++) {
				node = nodes[i];
				if (node.nodeName === 'SCRIPT') {
					if (node.getAttribute('v-src'))
						remote(node);
					else
						local(node);
					if (msie)
						IE_GC(node);
				} else {
					el.appendChild(node);
				}
			}

			if (remoteSize === 0 && done)
				done(el);

			function local(node) {
				var script = document.createElement('script');
				script.type = node.type || 'text/javascript';
				// for template
				if (node.id)
					script.id = node.id;
				// for IE cannot use 'innerHTML', just use 'text'
				script.text = node.text;
				el.appendChild(script);
			}

			// for script signature is httpBackend(node, url, type, callback, ajaxPort)
			function remote(node) {
				var url = getPath(node.getAttribute('v-src'), root), type = node.type || 'text/javascript';
				var doneWrapper = function(status, response, headers) {
					remoteCount++;
					if (done && remoteCount === remoteSize)
						scope.$apply(function() {
							done(el);
						}, 'script->' + url);
				};
				$httpBackend(el, url, type, doneWrapper, port);
			}

		}

	}

	// add form nested viewport process
	vViewportDirective.$inject = ['$targets'];
	function vViewportDirective($targets) {
		return {
			restrict : 'EA',
			scope : true,
			terminal : true,
			priority : 99,
			controller : vViewControllers.viewport,
			link : function(scope, element, attr, ctrl) {
				ctrl.$init();
				element.bind('$destroy', function() {
					ctrl.$destroy();
					cleanupClosure(ctrl);
				});
			}
		};
	}

	function vPageDirective() {
		return {
			restrict : 'EA',
			terminal : true, // disable page inner compile for lazy-compile
			require : ['vPage', '^vViewport'],
			priority : 99,
			controller : vViewControllers.page,
			link : function(scope, element, attr, ctrl) {
				ctrl[1].$addPage(ctrl[0]);
				element.bind('$destroy', function() {
					ctrl[0].$destroy();
					cleanupClosure(ctrl[0]);
				});
			}
		};
	}

	function vViewSetupDirective() {
		return {
			require : '^vViewport',
			controller : '@@'
		};
	}


	/*
	vTargetDirective.$inject = ['$targets', '$interpolate'];
	function vTargetDirective($targets, $interpolate) {
		return {
			restrict : 'A',
			link : function(scope, element, attr) {
				var target = attr.vTarget || attr.target || element.controller('vViewport'), href = element.attr('href');

				if (href) {
					var hrefFn = $interpolate(href);
					element.bind('click', function(event) {
						//scope.$apply(function() {
						var h = hrefFn(scope);
						$targets(target, h);
						//}, 'v-target');
						event.preventDefault();
						//event.stopPropagation();
					});
				}
			}
		};
	}
	*/

	/*
	vTrackDirective.$inject = ['$targets'];
	function vTrackDirective($targets) {
		return {
			restrict : 'A',
			link : function(scope, element, attr) {
				if (attr.vTrack) {
					var steps = attr.vTrack, readonly = isDefined(attr.readonly), //
					flag = steps.match(/^(#?)([\+\-]?)(\d+)$/), viewportCtrl = element.controller('vViewport');
					if (!flag)
						throw vError(109, 'invalid track format, require [#][+-]number: {0}', steps);
					var page = flag[1], relative = flag[2];
					if (page) {
						if (!viewportCtrl)
							throw vError(110, 'no parent viewport found for track prefix with "#"');
						steps = steps.substring(1);
					}
					var n = int(steps), disabled = false;
					if (relative) {
						steps = n > 0 ? '+1' : '-1';
					}

					if (!readonly) {
						element.bind('click', function(event) {
							//scope.$apply(function(){
							if (!disabled) {
								if (!page)
									$targets.track(steps);
								else
									viewportCtrl.$trackPage(steps, false);
							}
							//}, 'v-track');
							event.preventDefault();
							//event.stopPropagation();
						});
					}

					if (!page) {
						if (relative) {
							scope.$watch(function() {
								var t = $targets.track.info;
								return t.tracks.length + ':' + t.index;
							}, function(status) {
								var info = $targets.track.info;
								if (info.tracks.length < 2 || (relative === '-' && info.index === 1) || (relative === '+' && info.index === info.tracks.length)) {
									disable();
								} else {
									enable();
								}
							});
						}
					} else {
						scope.$watch(function() {
							var t = viewportCtrl.$pages;
							return t.activeMax + ':' + t.activeIndex;
						}, function(status) {
							var info = viewportCtrl.$pages;
							if (relative) {
								if (info.activeMax < 2 || (relative === '-' && info.activeIndex === 1) || (relative === '+' && info.activeIndex === info.activeMax)) {
									disable();
								} else {
									enable();
								}
							} else {
								if (n > viewportCtrl.$pages.activeMax) {
									disable();
								} else {
									enable();
								}
							}
						});
					}
				}

				function enable() {
					disabled = false;
					element.removeAttr('disabled');
					element.removeClass('v-disabled');
				}

				function disable() {
					disabled = true;
					element.attr('disabled', 'disabled');
					element.addClass('v-disabled');
				}

			}
		};
	}
	*/

	/**
	 * @vxdoc directive
	 * @name v.directive:vIf
	 * @restrict A
	 *
	 * @description
	 * The `vIf` directive removes and recreates a portion of the DOM tree (HTML)
	 * conditionally based on **"falsy"** and **"truthy"** values, respectively, evaluated within
	 * an {expression}. In other words, if the expression assigned to **vIf evaluates to a false
	 * value** then **the element is removed from the DOM** and **if true** then **a clone of the
	 * element is reinserted into the DOM**.
	 *
	 * `vIf` differs from `vShow` and `vHide` in that `vIf` completely removes and recreates the
	 * element in the DOM rather than changing its visibility via the `display` css property.  A common
	 * case when this difference is significant is when using css selectors that rely on an element's
	 * position within the DOM (HTML), such as the `:first-child` or `:last-child` pseudo-classes.
	 *
	 * Note that **when an element is removed using vIf its scope is destroyed** and **a new scope
	 * is created when the element is restored**.  The scope created within `vIf` inherits from
	 * its parent scope using prototypal inheritance.
	 * An important implication of this is if `vModel` is used within `vIf` to bind to
	 * a javascript primitive defined in the parent scope. In this case any modifications made to the
	 * variable within the child scope will override (hide) the value in the parent scope.
	 *
	 * Also, `vIf` recreates elements using their compiled state. An example scenario of this behavior
	 * is if an element's class attribute is directly modified after it's compiled, using something like
	 * jQuery's `.addClass()` method, and the element is later removed. When `vIf` recreates the element
	 * the added class will be lost because the original compiled state is used to regenerate the element.
	 *
	 * Additionally, you can provide animations via the vAnimate attribute to animate the **enter**
	 * and **leave** effects.
	 *
	 * @animations
	 * enter - happens just after the vIf contents change and a new DOM element is created and injected into the vIf container
	 * leave - happens just before the vIf contents are removed from the DOM
	 *
	 * @element ANY
	 * @scope
	 * @param {expression} vIf If the {@link guide/expression expression} is falsy then
	 *     the element is removed from the DOM tree (HTML).
	 *
	 * @example
	 <example animations="true">
	 <file name="index.html">
	 Click me: <input type="checkbox" v-model="checked" v-init="checked=true" /><br/>
	 Show when checked:
	 <span v-if="checked" v-animate="'example'">
	 I'm removed when the checkbox is unchecked.
	 </span>
	 </file>
	 <file name="animations.css">
	 .example-leave, .example-enter {
	 -webkit-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
	 -moz-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
	 -ms-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
	 -o-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
	 transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
	 }

	 .example-enter {
	 opacity:0;
	 }
	 .example-enter.example-enter-active {
	 opacity:1;
	 }

	 .example-leave {
	 opacity:1;
	 }
	 .example-leave.example-leave-active {
	 opacity:0;
	 }
	 </file>
	 </example>
	 */
	vIfDirective.$inject = ['$animator'];
	function vIfDirective($animator) {
		return {
			transclude : 'element',
			priority : 1000,
			terminal : true,
			restrict : 'A',
			compile : function(element, attr, transclude) {
				return function($scope, $element, $attr) {
					var animate = $animator($scope, $attr);
					var childElement, childScope;
					$scope.$watch($attr.vIf, function vIfWatchAction(value) {
						if (childElement) {
							animate.leave(childElement);
							childElement = undefined;
						}
						if (childScope) {
							childScope.$destroy();
							childScope = undefined;
						}
						if (toBoolean(value)) {
							childScope = $scope.$new();
							transclude(childScope, function(clone) {
								childElement = clone;
								animate.enter(clone, $element.parent(), $element);
							});
						}
					});
				};
			}
		};
	}

	/**
	 * @vxdoc directive
	 * @name vx.directive:vSwitch
	 * @restrict EA
	 *
	 * @description
	 * The vSwitch directive is used to conditionally swap DOM structure on your template based on a scope expression.
	 * Elements within vSwitch but without vSwitchWhen or vSwitchDefault directives will be preserved at the location
	 * as specified in the template.
	 *
	 * The directive itself works similar to vInclude, however, instead of downloading template code (or loading it
	 * from the template cache), vSwitch simply choses one of the nested elements and makes it visible based on which element
	 * matches the value obtained from the evaluated expression. In other words, you define a container element
	 * (where you place the directive), place an expression on the **on="..." attribute**
	 * (or the **v-switch="..." attribute**), define any inner elements inside of the directive and place
	 * a when attribute per element. The when attribute is used to inform vSwitch which element to display when the on
	 * expression is evaluated. If a matching expression is not found via a when attribute then an element with the default
	 * attribute is displayed.
	 *
	 * Additionally, you can also provide animations via the vAnimate attribute to animate the **enter**
	 * and **leave** effects.
	 *
	 * @animations
	 * enter - happens after the vSwtich contents change and the matched child element is placed inside the container
	 * leave - happens just after the vSwitch contents change and just before the former contents are removed from the DOM
	 *
	 * @usage
	 * <ANY v-switch="expression">
	 *   <ANY v-switch-when="matchValue1">...</ANY>
	 *   <ANY v-switch-when="matchValue2">...</ANY>
	 *   <ANY v-switch-default>...</ANY>
	 * </ANY>
	 *
	 * @scope
	 * @param {*} vSwitch|on expression to match against <tt>v-switch-when</tt>.
	 * @paramDescription
	 * On child elements add:
	 *
	 * * `vSwitchWhen`: the case statement to match against. If match then this
	 *   case will be displayed. If the same match appears multiple times, all the
	 *   elements will be displayed.
	 * * `vSwitchDefault`: the default case when no other case match. If there
	 *   are multiple default cases, all of them will be displayed when no other
	 *   case match.
	 *
	 * @example
	 <example animations="true">
	 <file name="index.html">
	 <div v-controller="Ctrl">
	 <select v-model="selection" v-options="item for item in items">
	 </select>
	 <tt>selection={{selection}}</tt>
	 <hr/>
	 <div
	 class="example-animate-container"
	 v-switch on="selection"
	 v-animate="{enter: 'example-enter', leave: 'example-leave'}">
	 <div v-switch-when="settings">Settings Div</div>
	 <div v-switch-when="home">Home Span</div>
	 <div v-switch-default>default</div>
	 </div>
	 </div>
	 </file>
	 <file name="script.js">
	 function Ctrl($scope) {
	 $scope.items = ['settings', 'home', 'other'];
	 $scope.selection = $scope.items[0];
	 }
	 </file>
	 <file name="animations.css">
	 .example-leave, .example-enter {
	 -webkit-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
	 -moz-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
	 -ms-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
	 -o-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
	 transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;

	 position:absolute;
	 top:0;
	 left:0;
	 right:0;
	 bottom:0;
	 }

	 .example-animate-container > * {
	 display:block;
	 padding:10px;
	 }

	 .example-enter {
	 top:-50px;
	 }
	 .example-enter-active.example-enter-active {
	 top:0;
	 }

	 .example-leave {
	 top:0;
	 }
	 .example-leave-active.example-leave-active {
	 top:50px;
	 }
	 </file>
	 <file name="scenario.js">
	 it('should start in settings', function() {
	 expect(element('.doc-example-live [v-switch]').text()).toMatch(/Settings Div/);
	 });
	 it('should change to home', function() {
	 select('selection').option('home');
	 expect(element('.doc-example-live [v-switch]').text()).toMatch(/Home Span/);
	 });
	 it('should select default', function() {
	 select('selection').option('other');
	 expect(element('.doc-example-live [v-switch]').text()).toMatch(/default/);
	 });
	 </file>
	 </example>
	 */
	/*
	vSwitchDirective.$inject = ['$animator'];
	function vSwitchDirective($animator) {
		return {
			restrict : 'EA',
			require : 'vSwitch',
			// asks for $scope to fool the BC controller module
			controller : ['$scope',
			function vSwitchController() {
				this.cases = {};
			}],
			link : function(scope, element, attr, vSwitchController) {
				var animate = $animator(scope, attr);
				var watchExpr = attr.vSwitch || attr.on, selectedTranscludes, selectedElements, selectedScopes = [];

				scope.$watch(watchExpr, function vSwitchWatchAction(value) {
					for (var i = 0, ii = selectedScopes.length; i < ii; i++) {
						selectedScopes[i].$destroy();
						animate.leave(selectedElements[i]);
					}
					selectedElements = [];
					selectedScopes = [];

					if (( selectedTranscludes = vSwitchController.cases['!' + value] || vSwitchController.cases['?'])) {
						scope.$eval(attr.change);
						forEach(selectedTranscludes, function(selectedTransclude) {
							var selectedScope = scope.$new();
							selectedScopes.push(selectedScope);
							selectedTransclude.transclude(selectedScope, function(caseElement) {
								var anchor = selectedTransclude.element;
								selectedElements.push(caseElement);
								animate.enter(caseElement, anchor.parent(), anchor);
							});
						});
					}
				});
			}
		};
	}
	*/

	function vSwitchWhenDirective() {
		return {
			restrict : 'AC',
			transclude : 'element',
			priority : 500,
			require : '^vSwitch',
			compile : function(element, attrs, transclude) {
				return function(scope, element, attr, ctrl) {
					ctrl.cases['!' + attrs.vSwitchWhen] = (ctrl.cases['!' + attrs.vSwitchWhen] || []);
					ctrl.cases['!' + attrs.vSwitchWhen].push({
						transclude : transclude,
						element : element
					});
				};
			}
		};
	}

	function vSwitchDefaultDirective() {
		return {
			restrict : 'AC',
			transclude : 'element',
			priority : 500,
			require : '^vSwitch',
			compile : function(element, attrs, transclude) {
				return function(scope, element, attr, ctrl) {
					ctrl.cases['?'] = (ctrl.cases['?'] || []);
					ctrl.cases['?'].push({
						transclude : transclude,
						element : element
					});
				};
			}
		};
	}

	/**
	 * @vxdoc directive
	 * @name vx.directive:a
	 * @restrict E
	 *
	 * @description
	 * Modifies the default behavior of html A tag, so that the default action is prevented when href
	 * attribute is empty.
	 *
	 * The reasoning for this change is to allow easy creation of action links with `vClick` directive
	 * without changing the location or causing page reloads, e.g.:
	 * `<a href="" v-click="model.$save()">Save</a>`
	 */
	function htmlAnchorDirective() {
		return {
			restrict : 'E',
			compile : function(element, attr) {
				if (msie <= 8) {
					// turn <a href v-click="..">link</a> into a stylable link in IE
					// but only if it doesn't have name attribute, in which case it's an anchor
					if (!attr.href && !attr.name) {
						attr.$set('href', '');
					}
					// add a comment node to anchors to workaround IE bug that causes element content to be reset
					// to new attribute content if attribute is updated with value containing @ and element also
					// contains value with @
					// see issue #1949
					element.append(document.createComment('IE fix'));
				}

				return function(scope, element) {
					// if we have no href url, then don't navigate anywhere.
					if (!element.attr('href')) {
						element.bind('click', function(event) {
							event.preventDefault();
							//event.stopPropagation();
							//return false;
							// Needed for opera
						});
					}
				};
			}
		};
	}

	/**
	 * @vxdoc directive
	 * @name vx.directive:vRepeat
	 *
	 * @description
	 * The `vRepeat` directive instantiates a template once per item from a collection. Each template
	 * instance gets its own scope, where the given loop variable is set to the current collection item,
	 * and `$index` is set to the item index or key.
	 *
	 * Special properties are exposed on the local scope of each template instance, including:
	 *
	 * | Variable  | Type            | Details                                                                     |
	 * |===========|=================|=============================================================================|
	 * | `$index`  | {@type number}  | iterator offset of the repeated element (0..length-1)                       |
	 * | `$first`  | {@type boolean} | true if the repeated element is first in the iterator.                      |
	 * | `$middle` | {@type boolean} | true if the repeated element is between the first and last in the iterator. |
	 * | `$last`   | {@type boolean} | true if the repeated element is last in the iterator.                       |
	 *
	 * Additionally, you can also provide animations via the vAnimate attribute to animate the **enter**,
	 * **leave** and **move** effects.
	 *
	 * @animations
	 * enter - when a new item is added to the list or when an item is revealed after a filter
	 * leave - when an item is removed from the list or when an item is filtered out
	 * move - when an adjacent item is filtered out causing a reorder or when the item contents are reordered
	 *
	 * @element ANY
	 * @scope
	 * @priority 1000
	 * @param {repeat_expression} vRepeat The expression indicating how to enumerate a collection. These
	 *   formats are currently supported:
	 *
	 *   * `variable in expression` – where variable is the user defined loop variable and `expression`
	 *     is a scope expression giving the collection to enumerate.
	 *
	 *     For example: `track in cd.tracks`.
	 *
	 *   * `(key, value) in expression` – where `key` and `value` can be any user defined identifiers,
	 *     and `expression` is the scope expression giving the collection to enumerate.
	 *
	 *     For example: `(name, age) in {'adam':10, 'amalie':12}`.
	 *
	 *   * `variable in expression track by tracking_expression` – You can also provide an optional tracking function
	 *     which can be used to associate the objects in the collection with the DOM elements. If no tractking function
	 *     is specified the v-repeat associates elements by identity in the collection. It is an error to have
	 *     more then one tractking function to  resolve to the same key. (This would mean that two distinct objects are
	 *     mapped to the same DOM element, which is not possible.)
	 *
	 *     For example: `item in items` is equivalent to `item in items track by $id(item)'. This implies that the DOM elements
	 *     will be associated by item identity in the array.
	 *
	 *     For example: `item in items track by $id(item)`. A built in `$id()` function can be used to assign a unique
	 *     `$$hashKey` property to each item in the array. This property is then used as a key to associated DOM elements
	 *     with the corresponding item in the array by identity. Moving the same object in array would move the DOM
	 *     element in the same way ian the DOM.
	 *
	 *     For example: `item in items track by item.id` Is a typical pattern when the items come from the database. In this
	 *     case the object identity does not matter. Two objects are considered equivalent as long as their `id`
	 *     property is same.
	 *
	 * @example
	 * This example initializes the scope to a list of names and
	 * then uses `vRepeat` to display every person:
	 <example animations="true">
	 <file name="index.html">
	 <div v-init="friends = [
	 {name:'John', age:25, gender:'boy'},
	 {name:'Jessie', age:30, gender:'girl'},
	 {name:'Johanna', age:28, gender:'girl'},
	 {name:'Joy', age:15, gender:'girl'},
	 {name:'Mary', age:28, gender:'girl'},
	 {name:'Peter', age:95, gender:'boy'},
	 {name:'Sebastian', age:50, gender:'boy'},
	 {name:'Erika', age:27, gender:'girl'},
	 {name:'Patrick', age:40, gender:'boy'},
	 {name:'Samantha', age:60, gender:'girl'}
	 ]">
	 I have {{friends.length}} friends. They are:
	 <input type="search" v-model="q" placeholder="filter friends..." />
	 <ul>
	 <li v-repeat="friend in friends | filter:q"
	 v-animate="{enter: 'example-repeat-enter',
	 leave: 'example-repeat-leave',
	 move: 'example-repeat-move'}">
	 [{{$index + 1}}] {{friend.name}} who is {{friend.age}} years old.
	 </li>
	 </ul>
	 </div>
	 </file>
	 <file name="animations.css">
	 .example-repeat-enter,
	 .example-repeat-leave,
	 .example-repeat-move {
	 -webkit-transition:all linear 0.5s;
	 -moz-transition:all linear 0.5s;
	 -ms-transition:all linear 0.5s;
	 -o-transition:all linear 0.5s;
	 transition:all linear 0.5s;
	 }

	 .example-repeat-enter {
	 line-height:0;
	 opacity:0;
	 }
	 .example-repeat-enter.example-repeat-enter-active {
	 line-height:20px;
	 opacity:1;
	 }

	 .example-repeat-leave {
	 opacity:1;
	 line-height:20px;
	 }
	 .example-repeat-leave.example-repeat-leave-active {
	 opacity:0;
	 line-height:0;
	 }

	 .example-repeat-move { }
	 .example-repeat-move.example-repeat-move-active { }
	 </file>
	 <file name="scenario.js">
	 it('should render initial data set', function() {
	 var r = using('.doc-example-live').repeater('ul li');
	 expect(r.count()).toBe(10);
	 expect(r.row(0)).toEqual(["1","John","25"]);
	 expect(r.row(1)).toEqual(["2","Jessie","30"]);
	 expect(r.row(9)).toEqual(["10","Samantha","60"]);
	 expect(binding('friends.length')).toBe("10");
	 });

	 it('should update repeater when filter predicate changes', function() {
	 var r = using('.doc-example-live').repeater('ul li');
	 expect(r.count()).toBe(10);

	 input('q').enter('ma');

	 expect(r.count()).toBe(2);
	 expect(r.row(0)).toEqual(["1","Mary","28"]);
	 expect(r.row(1)).toEqual(["2","Samantha","60"]);
	 });
	 </file>
	 </example>
	 */
	vRepeatDirective.$inject = ['$parse', '$animator'];
	function vRepeatDirective($parse, $animator) {
		var V_REMOVED = '$$V_REMOVED';
		return {
			transclude : 'element',
			priority : 1000,
			terminal : true,
			compile : function(element, attr, linker) {
				return function($scope, $element, $attr) {
					var animate = $animator($scope, $attr);
					var expression = $attr.vRepeat;
					var match = expression.match(/^\s*(.+)\s+in\s+(.*?)\s*(\s+track\s+by\s+(.+)\s*)?$/), trackByExp, trackByExpGetter, trackByIdFn, lhs, rhs, //
					valueIdentifier, keyIdentifier, hashFnLocals = {
						$id : hashKey
					};

					if (!match) {
						throw vError(111, "vRepeat error! Expected expression in form of '_item_ in _collection_[ track by _id_]' but got '{0}'.", expression);
					}

					lhs = match[1];
					rhs = match[2];
					trackByExp = match[4];

					if (trackByExp) {
						trackByExpGetter = $parse(trackByExp);
						trackByIdFn = function(key, value, index) {
							// assign key, value, and $index to the locals so that they can be used in hash functions
							if (keyIdentifier)
								hashFnLocals[keyIdentifier] = key;
							hashFnLocals[valueIdentifier] = value;
							hashFnLocals.$index = index;
							return trackByExpGetter($scope, hashFnLocals);
						};
					} else {
						trackByIdFn = function(key, value) {
							return hashKey(value);
						};
					}

					match = lhs.match(/^(?:([\$\w]+)|\(([\$\w]+)\s*,\s*([\$\w]+)\))$/);
					if (!match) {
						throw vError(112, "vRepeat error! '_item_' in '_item_ in _collection_' should be an identifier or '(_key_, _value_)' expression, but got '{0}'.", lhs);
					}
					valueIdentifier = match[3] || match[1];
					keyIdentifier = match[2];

					// Store a list of elements from previous run. This is a hash where key is the item from the
					// iterator, and the value is objects with following properties.
					//   - scope: bound scope
					//   - element: previous element.
					//   - index: position
					var lastBlockMap = {};

					//watch props
					$scope.$watchCollection(rhs, function vRepeatAction(collection) {
						var index, length, cursor = $element, // current position of the node
						nextCursor,
						// Same as lastBlockMap but it has the current state. It will become the
						// lastBlockMap on the next iteration.
						nextBlockMap = {}, arrayLength, childScope, key, value, // key/value of iteration
						trackById, collectionKeys, block, // last object information {scope, element, id}
						nextBlockOrder = [];

						if (isArrayLike(collection)) {
							collectionKeys = collection;
						} else {
							// if object, extract keys, sort them and use to determine order of iteration over obj props
							collectionKeys = [];
							for (key in collection) {
								if (collection.hasOwnProperty(key) && key.charAt(0) != '$') {
									collectionKeys.push(key);
								}
							}
							collectionKeys.sort();
						}

						arrayLength = collectionKeys.length;

						// locate existing items
						length = nextBlockOrder.length = collectionKeys.length;
						for ( index = 0; index < length; index++) {
							key = (collection === collectionKeys) ? index : collectionKeys[index];
							value = collection[key];
							trackById = trackByIdFn(key, value, index);
							if (lastBlockMap.hasOwnProperty(trackById)) {
								block = lastBlockMap[trackById];
								delete lastBlockMap[trackById];
								nextBlockMap[trackById] = block;
								nextBlockOrder[index] = block;
							} else if (nextBlockMap.hasOwnProperty(trackById)) {
								// restore lastBlockMap
								/*jshint loopfunc:true */
								forEach(nextBlockOrder, function(block) {
									if (block && block.element)
										lastBlockMap[block.id] = block;
								});
								// This is a duplicate and we need to throw an error
								throw vError(113, "vRepeat error! Duplicates in a repeater are not allowed. Use 'track by' expression to specify unique keys. Repeater: {0}, Duplicate key: {1}", expression, trackById);
							} else {
								// new never before seen block
								nextBlockOrder[index] = {
									id : trackById
								};
								nextBlockMap[trackById] = false;
							}
						}

						// remove existing items
						for (key in lastBlockMap) {
							if (lastBlockMap.hasOwnProperty(key)) {
								block = lastBlockMap[key];
								animate.leave(block.element);
								forEach(block.element, function(element) {
									element[V_REMOVED] = true;
								});
								block.scope.$destroy();
							}
						}

						// we are not using forEach for perf reasons (trying to avoid #call)
						for ( index = 0, length = collectionKeys.length; index < length; index++) {
							key = (collection === collectionKeys) ? index : collectionKeys[index];
							value = collection[key];
							block = nextBlockOrder[index];

							if (block.element) {
								// if we have already seen this object, then we need to reuse the
								// associated scope/element
								childScope = block.scope;

								nextCursor = cursor[0];
								do {
									nextCursor = nextCursor.nextSibling;
								} while(nextCursor && nextCursor[V_REMOVED]);

								if (block.element[0] == nextCursor) {
									// do nothing
									cursor = block.element;
								} else {
									// existing item which got moved
									animate.move(block.element, null, cursor);
									cursor = block.element;
								}
							} else {
								// new item which we don't know about
								childScope = $scope.$new();
							}

							childScope[valueIdentifier] = value;
							if (keyIdentifier)
								childScope[keyIdentifier] = key;
							childScope.$index = index;
							childScope.$first = (index === 0);
							childScope.$last = (index === (arrayLength - 1));
							childScope.$middle = !(childScope.$first || childScope.$last);

							if (!block.element) {
								linker(childScope, function(clone) {
									animate.enter(clone, null, cursor);
									cursor = clone;
									block.scope = childScope;
									block.element = clone;
									nextBlockMap[block.id] = block;
								});
							}
						}
						lastBlockMap = nextBlockMap;
					}, true);
				};
			}
		};
	}

	/**
	 * @vxdoc directive
	 * @name vx.directive:vNonBindable
	 * @priority 1000
	 *
	 * @description
	 * Sometimes it is necessary to write code which looks like bindings but which should be left alone
	 * by vx. Use `vNonBindable` to make vx ignore a chunk of HTML.
	 *
	 * @element ANY
	 *
	 * @example
	 * In this example there are two location where a simple binding (`{{}}`) is present, but the one
	 * wrapped in `vNonBindable` is left alone.
	 *
	 * @example
	 <doc:example>
	 <doc:source>
	 <div>Normal: {{1 + 2}}</div>
	 <div v-non-bindable>Ignored: {{1 + 2}}</div>
	 </doc:source>
	 <doc:scenario>
	 it('should check v-non-bindable', function() {
	 expect(using('.doc-example-live').binding('1 + 2')).toBe('3');
	 expect(using('.doc-example-live').element('div:last').text()).
	 toMatch(/1 \+ 2/);
	 });
	 </doc:scenario>
	 </doc:example>
	 */
	/*
	function vNonBindableDirective() {
		return {
			restrict : 'AC',
			terminal : true,
			priority : 1000
		};
	}
	*/

	/**
	 * @vxdoc directive
	 * @name vx.directive:script
	 *
	 * @description
	 * Load content of a script tag, with type `text/v-template`, into `$templateCache`, so that the
	 * template can be used by `vInclude`, `vView` or directive templates.
	 *
	 * @restrict E
	 * @param {'text/v-template'} type must be set to `'text/v-template'`
	 *
	 * @example
	 <doc:example>
	 <doc:source>
	 <script type="text/v-template" id="/tpl.html">
	 Content of the template.
	 </script>

	 <a v-click="currentTpl='/tpl.html'" id="tpl-link">Load inlined template</a>
	 <div id="tpl-content" v-include src="currentTpl"></div>
	 </doc:source>
	 <doc:scenario>
	 it('should load template defined inside script tag', function() {
	 element('#tpl-link').click();
	 expect(element('#tpl-content').text()).toMatch(/Content of the template/);
	 });
	 </doc:scenario>
	 </doc:example>
	 */
	scriptDirective.$inject = ['$templateCache'];
	function scriptDirective($templateCache) {
		return {
			restrict : 'E',
			terminal : true,
			compile : function(element, attr) {
				if (attr.type == 'text/v-template') {
					var templateUrl = attr.id,
					// IE is not consistent, in scripts we have to read .text but in other nodes we have to read .textContent
					text = element[0].text;

					$templateCache.put(templateUrl, text);
				}
			}
		};
	}

	var nullFormCtrl = {
		$addControl : noop,
		$removeControl : noop,
		$setValidity : noop,
		$setDirty : noop,
		$setPristine : noop,
		$getData : noop,
		$getError : noop,
		$clearData : noop
	};

	function isValidItem(data) {
		if (data == null)
			return false;
		if (!isObject(data) || !!data.$selected)
			return true;
		return false;
	}

	var VALID_CLASS = 'v-valid', INVALID_CLASS = 'v-invalid', PRISTINE_CLASS = 'v-pristine', DIRTY_CLASS = 'v-dirty';

	/**
	 * @vxdoc object
	 * @name vx.directive:form.FormController
	 *
	 * @property {boolean} $pristine True if user has not interacted with the form yet.
	 * @property {boolean} $dirty True if user has already interacted with the form.
	 * @property {boolean} $valid True if all of the containing forms and controls are valid.
	 * @property {boolean} $invalid True if at least one containing control or form is invalid.
	 *
	 * @property {Object} $error Is an object hash, containing references to all invalid controls or
	 *  forms, where:
	 *
	 *  - keys are validation tokens (error names) — such as `required`, `url` or `email`),
	 *  - values are arrays of controls or forms that are invalid with given error.
	 *
	 * @description
	 * `FormController` keeps track of all its controls and nested forms as well as state of them,
	 * such as being valid/invalid or dirty/pristine.
	 *
	 * Each {@link vx.directive:form form} directive creates an instance
	 * of `FormController`.
	 *
	 */
	//asks for $scope to fool the BC controller module
	FormController.$inject = ['$element', '$attrs', '$parse', '$scope'];
	function FormController(element, attrs, $parse) {
		var form = this, invalidCount = 0, // used to easily determine if we are valid
		errors = form.$error = {}, controls = form.$controls = [];

		var parentForm = element.parent().controller('form') || nullFormCtrl;

		// init state
		form.$name = attrs.name || attrs.vForm;
		form.$dirty = false;
		form.$pristine = true;
		form.$valid = true;
		form.$invalid = false;

		form.$virtual = _nodeName(element) !== 'FORM';

		// Setup initial state of the control
		element.addClass(PRISTINE_CLASS);
		toggleValidCss(element, true);

		form.$submit = function() {
			element.trigger('submit');
		};

		form.$getData = (function formData() {

			function formArray(data) {
				var ret = [];
				for (var i = 0, d; i < data.length; i++) {
					if (isValidItem(data[i])) {
						d = copy(data[i]);
						ret.push(d);
					}
				}
				return ret;
			}

			function putData(data, name, value) {
				var expr = $parse(name + "=tmp");
				expr(data, {
					tmp : value
				});
			}

			return function(parent) {
				var data = {}, pdata = {};
				if (!!parent) {
					pdata = parentForm.$getData();
				}
				forEach(controls, function(model) {
					if (model.$name) {
						if (!model.$parentModel) {
							var value = model.$modelValue;
							if (isEmpty(value))
								return;
							if (model.$virtual) {
								value = formArray(value);
								if (value.length === 0)
									return;
							}
							putData(data, model.$name, value);
						}
					}
				});
				return extend({}, pdata, data);
			};

		})();

		form.$getError = function(parent) {
			var errs;
			if (parent)
				errs = extend({}, parentForm.$error, form.$error);
			else
				errs = extend({}, form.$error);
			return size(errs, true) ? errs : null;
		};
		form.$clearData = function() {
			forEach(controls, function(ctrl) {
				if (ctrl.$name) {
					if (!ctrl.$parentModel) {
						if (ctrl.$virtual) {
							for (var i = 0, d; i < ctrl.$modelValue.length; i++) {
								delete ctrl.$modelValue[i].$selected;
							}
						} else {
							ctrl.$reset();
						}
					}
				}
			});
		};

		// convenience method for easy toggling of classes
		function toggleValidCss(element, isValid, validationErrorKey) {
			validationErrorKey = validationErrorKey ? '-' + snake_case(validationErrorKey, '-') : '';
			element.removeClass(( isValid ? INVALID_CLASS : VALID_CLASS) + validationErrorKey).addClass(( isValid ? VALID_CLASS : INVALID_CLASS) + validationErrorKey);
		}


		form.$addControl = function(control, attr) {
			controls.push(control);
			// if same name, just add first one
			if (control.$name) {
				if (!form.hasOwnProperty(control.$name)) {
					form[control.$name] = control;
				}
				var watchFn = function(value) {
					var oldName = control.$name;
					if (oldName === value)
						return;
					var old = form[oldName];
					control.$name = value;
					if (old === control) {
						delete form[oldName];
						form[control.$name] = control;
					}
				};
				attr.$observe('name', watchFn);
			}
		};

		form.$removeControl = function(control) {
			if (control.$name && form[control.$name] === control) {
				delete form[control.$name];
			}
			forEach(errors, function(queue, validationToken) {
				form.$setValidity(validationToken, true, control);
			});
			arrayRemove(controls, control);
		};

		form.$setValidity = function(validationToken, isValid, control) {
			var queue = errors[validationToken];
			if (isValid) {
				if (queue) {
					arrayRemove(queue, control);
					if (!queue.length) {
						invalidCount--;
						if (!invalidCount) {
							toggleValidCss(element, isValid);
							form.$valid = true;
							form.$invalid = false;
						}
						//errors[validationToken] = false;
						delete errors[validationToken];
						toggleValidCss(element, true, validationToken);
					}
				}
			} else {
				if (!invalidCount) {
					toggleValidCss(element, isValid);
				}
				if (queue) {
					if (includes(queue, control))
						return;
				} else {
					errors[validationToken] = queue = [];
					invalidCount++;
					toggleValidCss(element, false, validationToken);
				}
				queue.push(control);
				form.$valid = false;
				form.$invalid = true;
			}
		};

		form.$setDirty = function() {
			element.removeClass(PRISTINE_CLASS).addClass(DIRTY_CLASS);
			form.$dirty = true;
			form.$pristine = false;
		};

		/**
		 * @vxdoc function
		 * @name v.directive:form.FormController#$setPristine
		 * @methodOf v.directive:form.FormController
		 *
		 * @description
		 * Sets the form to its pristine state.
		 *
		 * This method can be called to remove the 'v-dirty' class and set the form to its pristine
		 * state (v-pristine class). This method will also propagate to all the controls contained
		 * in this form.
		 *
		 * Setting a form back to a pristine state is often useful when we want to 'reuse' a form after
		 * saving or resetting it.
		 */
		form.$setPristine = function() {
			element.removeClass(DIRTY_CLASS).addClass(PRISTINE_CLASS);
			form.$dirty = false;
			form.$pristine = true;
			forEach(controls, function(control) {
				control.$setPristine();
			});
		};

	}

	/**
	 * @vxdoc directive
	 * @name vx.directive:vForm
	 * @restrict EAC
	 *
	 * @description
	 * Nestable alias of {@link vx.directive:form `form`} directive. HTML
	 * does not allow nesting of form elements. It is useful to nest forms, for example if the validity of a
	 * sub-group of controls needs to be determined.
	 *
	 * @param {string=} name|vForm Name of the form. If specified, the form controller will be published into
	 *                       related scope, under this name.
	 *
	 */

	/**
	 * @vxdoc directive
	 * @name vx.directive:form
	 * @restrict E
	 *
	 * @description
	 * Directive that instantiates
	 * {@link vx.directive:form.FormController FormController}.
	 *
	 * If `name` attribute is specified, the form controller is published onto the current scope under
	 * this name.
	 *
	 * # Alias: {@link vx.directive:vForm `vForm`}
	 *
	 * In vx forms can be nested. This means that the outer form is valid when all of the child
	 * forms are valid as well. However browsers do not allow nesting of `<form>` elements, for this
	 * reason vx provides {@link vx.directive:vForm `vForm`} alias
	 * which behaves identical to `<form>` but allows form nesting.
	 *
	 *
	 * # CSS classes
	 *  - `v-valid` Is set if the form is valid.
	 *  - `v-invalid` Is set if the form is invalid.
	 *  - `v-pristine` Is set if the form is pristine.
	 *  - `v-dirty` Is set if the form is dirty.
	 *
	 *
	 * # Submitting a form and preventing default action
	 *
	 * Since the role of forms in client-side VX applications is different than in classical
	 * roundtrip apps, it is desirable for the browser not to translate the form submission into a full
	 * page reload that sends the data to the server. Instead some javascript logic should be triggered
	 * to handle the form submission in application specific way.
	 *
	 * For this reason, VX prevents the default action (form submission to the server) unless the
	 * `<form>` element has an `action` attribute specified.
	 *
	 * You can use one of the following two ways to specify what javascript method should be called when
	 * a form is submitted:
	 *
	 * - {@link vx.directive:vSubmit vSubmit} directive on the form element
	 * - {@link vx.directive:vClick vClick} directive on the first
	 *  button or input field of type submit (input[type=submit])
	 *
	 * To prevent double execution of the handler, use only one of vSubmit or vClick directives. This
	 * is because of the following form submission rules coming from the html spec:
	 *
	 * - If a form has only one input field then hitting enter in this field triggers form submit
	 * (`vSubmit`)
	 * - if a form has has 2+ input fields and no buttons or input[type=submit] then hitting enter
	 * doesn't trigger submit
	 * - if a form has one or more input fields and one or more buttons or input[type=submit] then
	 * hitting enter in any of the input fields will trigger the click handler on the *first* button or
	 * input[type=submit] (`vClick`) *and* a submit handler on the enclosing form (`vSubmit`)
	 *
	 * @param {string=} name Name of the form. If specified, the form controller will be published into
	 *                       related scope, under this name.
	 *
	 * @example
	 <doc:example>
	 <doc:source>
	 <script>
	 function Ctrl($scope) {
	 $scope.userType = 'guest';
	 }
	 </script>
	 <form name="myForm" v-controller="Ctrl">
	 userType: <input name="input" v-model="userType" required>
	 <span class="error" v-show="myForm.input.$error.required">Required!</span><br>
	 <tt>userType = {{userType}}</tt><br>
	 <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br>
	 <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br>
	 <tt>myForm.$valid = {{myForm.$valid}}</tt><br>
	 <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br>
	 </form>
	 </doc:source>
	 <doc:scenario>
	 it('should initialize to model', function() {
	 expect(binding('userType')).toEqual('guest');
	 expect(binding('myForm.input.$valid')).toEqual('true');
	 });

	 it('should be invalid if empty', function() {
	 input('userType').enter('');
	 expect(binding('userType')).toEqual('');
	 expect(binding('myForm.input.$valid')).toEqual('false');
	 });
	 </doc:scenario>
	 </doc:example>
	 */
	function formDirectiveFactory(isVForm) {
		factory.$inject = ['$$remote'];
		function factory($$remote) {
			var formDirective = {
				name : 'form',
				restrict : 'E',
				controller : FormController,
				compile : function() {
					return {
						pre : function(scope, formElement, attr, controller) {
							if (!attr.action) {
								formElement.bind('submit', function(event) {
									event.preventDefault();
									//event.stopPropagation();
								});
							}

							if (attr.action) {
								var parent = attr.parent === 'true', model = attr.model || '$result';
								var act = trim(attr.action);
								var $remote = $$remote(formElement, true);
								formElement.bind('submit', function(event) {
									// forbid cascade submit
									if (event.target !== formElement[0]) {
										var formCtrl0 = jqLite(event.target).controller('form');
										if (controller !== formCtrl0)
											return;
									}
									if (!controller.$getError(parent)) {
										//scope.$apply(function() {
										var data = controller.$getData(parent);
										var q = $remote.post(act, data, model);
										if (attr.href) {
											var target = trim(attr.href);
											q.forward(attr.target || formElement.controller('vViewport'), target);
										}
										//}, isVForm ? 'v-form' : 'form');
									}
									event.preventDefault();
									//event.stopPropagation();
								});
							}

							var page = formElement.controller('vPage');
							if (page)
								page.$addForm(controller);

							var bind = controller.$bind = function() {
								var fname = controller.$name;
								if (fname) {
									if (scope[fname])
										throw vError(114, 'scope has duplicated form name: {0}', fname);
									scope[fname] = controller;
									return true;
								}
								return false;
							};

							if (bind()) {
								var attachFn = function attachFn(key) {
									return function(value) {
										var oldName = controller.$name;
										if (oldName === value)
											return;
										if (oldName/* && controller === scope[oldName]*/) {
											delete scope[oldName];
										}
										if (scope[value])
											throw vError(115, 'scope has duplicated form name: {0}', value);
										scope[value] = controller;
										controller.$name = value;
									};
								};
								if (!isVForm)
									attr.$observe('name', attachFn('name'));
								else
									attr.$observe('vForm', attachFn('vForm'));
							}

							var unbind = controller.$unbind = function() {
								var name = controller.$name;
								if (name/* && controller === scope[name]*/) {
									delete scope[name];
								}
							};

							formElement.bind('$destroy', function() {
								unbind();
								if (page)
									page.$removeForm(controller);
								//stop propagating child destruction handlers upwards
								//extend(controller, nullFormCtrl);
								cleanupClosure(controller);
							});

						}
					};
				}
			};
			return isVForm ? extend(copy(formDirective), {
				restrict : 'EAC'
			}) : formDirective;
		}

		return factory;
	}

	var formDirective = formDirectiveFactory();
	//var vFormDirective = formDirectiveFactory(true);

	/**
	 * @vxdoc directive
	 * @name vx.directive:textarea
	 * @restrict E
	 *
	 * @description
	 * HTML textarea element control with vx data-binding. The data-binding and validation
	 * properties of this element are exactly the same as those of the
	 * {@link vx.directive:input input element}.
	 *
	 * @param {string} vModel Assignable vx expression to data-bind to.
	 * @param {string=} name Property name of the form under which the control is published.
	 * @param {string=} required Adds `required` validation error key if the value is not entered.
	 * @param {string=} vRequired Adds `required` attribute and `required` validation constraint to
	 *    the element when the vRequired expression evaluates to true. Use `vRequired` instead of
	 *    `required` when you want to data-bind to the `required` attribute.
	 * @param {number=} vMinlength Sets `minlength` validation error key if the value is shorter than
	 *    minlength.
	 * @param {number=} vMaxlength Sets `maxlength` validation error key if the value is longer than
	 *    maxlength.
	 * @param {string=} vPattern Sets `pattern` validation error key if the value does not match the
	 *    RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
	 *    patterns defined as scope expressions.
	 * @param {string=} vChange VX expression to be executed when input changes due to user
	 *    interaction with the input element.
	 */

	/**
	 * @vxdoc directive
	 * @name vx.directive:input
	 * @restrict E
	 *
	 * @description
	 * HTML input element control with vx data-binding. Input control follows HTML5 input types
	 * and polyfills the HTML5 validation behavior for older browsers.
	 *
	 * @param {string} vModel Assignable vx expression to data-bind to.
	 * @param {string=} name Property name of the form under which the control is published.
	 * @param {number=} vMinlength Sets `minlength` validation error key if the value is shorter than
	 *    minlength.
	 * @param {number=} vMaxlength Sets `maxlength` validation error key if the value is longer than
	 *    maxlength.
	 * @param {string=} vPattern Sets `pattern` validation error key if the value does not match the
	 *    RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
	 *    patterns defined as scope expressions.
	 * @param {string=} vChange VX expression to be executed when input changes due to user
	 *    interaction with the input element.
	 *
	 * @example
	 <doc:example>
	 <doc:source>
	 <script>
	 function Ctrl($scope) {
	 $scope.user = {name: 'guest', last: 'visitor'};
	 }
	 </script>
	 <div v-controller="Ctrl">
	 <form name="myForm">
	 User name: <input type="text" name="userName" v-model="user.name" required>
	 <span class="error" v-show="myForm.userName.$error.required">
	 Required!</span><br>
	 Last name: <input type="text" name="lastName" v-model="user.last"
	 v-minlength="3" v-maxlength="10">
	 <span class="error" v-show="myForm.lastName.$error.minlength">
	 Too short!</span>
	 <span class="error" v-show="myForm.lastName.$error.maxlength">
	 Too long!</span><br>
	 </form>
	 <hr>
	 <tt>user = {{user}}</tt><br/>
	 <tt>myForm.userName.$valid = {{myForm.userName.$valid}}</tt><br>
	 <tt>myForm.userName.$error = {{myForm.userName.$error}}</tt><br>
	 <tt>myForm.lastName.$valid = {{myForm.lastName.$valid}}</tt><br>
	 <tt>myForm.lastName.$error = {{myForm.lastName.$error}}</tt><br>
	 <tt>myForm.$valid = {{myForm.$valid}}</tt><br>
	 <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br>
	 <tt>myForm.$error.minlength = {{!!myForm.$error.minlength}}</tt><br>
	 <tt>myForm.$error.maxlength = {{!!myForm.$error.maxlength}}</tt><br>
	 </div>
	 </doc:source>
	 <doc:scenario>
	 it('should initialize to model', function() {
	 expect(binding('user')).toEqual('{"name":"guest","last":"visitor"}');
	 expect(binding('myForm.userName.$valid')).toEqual('true');
	 expect(binding('myForm.$valid')).toEqual('true');
	 });

	 it('should be invalid if empty when required', function() {
	 input('user.name').enter('');
	 expect(binding('user')).toEqual('{"last":"visitor"}');
	 expect(binding('myForm.userName.$valid')).toEqual('false');
	 expect(binding('myForm.$valid')).toEqual('false');
	 });

	 it('should be valid if empty when min length is set', function() {
	 input('user.last').enter('');
	 expect(binding('user')).toEqual('{"name":"guest","last":""}');
	 expect(binding('myForm.lastName.$valid')).toEqual('true');
	 expect(binding('myForm.$valid')).toEqual('true');
	 });

	 it('should be invalid if less than required min length', function() {
	 input('user.last').enter('xx');
	 expect(binding('user')).toEqual('{"name":"guest"}');
	 expect(binding('myForm.lastName.$valid')).toEqual('false');
	 expect(binding('myForm.lastName.$error')).toMatch(/minlength/);
	 expect(binding('myForm.$valid')).toEqual('false');
	 });

	 it('should be invalid if longer than max length', function() {
	 input('user.last').enter('some ridiculously long name');
	 expect(binding('user'))
	 .toEqual('{"name":"guest"}');
	 expect(binding('myForm.lastName.$valid')).toEqual('false');
	 expect(binding('myForm.lastName.$error')).toMatch(/maxlength/);
	 expect(binding('myForm.$valid')).toEqual('false');
	 });
	 </doc:scenario>
	 </doc:example>
	 */
	inputDirective.$inject = ['$browser', '$sniffer', '$validation', '$log'];
	function inputDirective($browser, $sniffer, $validation, $log) {

		var inputType = {

			/**
			 * @vxdoc inputType
			 * @name vx.directive:input.text
			 *
			 * @description
			 * Standard HTML text input with vx data binding.
			 *
			 * @param {string} vModel Assignable vx expression to data-bind to.
			 * @param {string=} name Property name of the form under which the control is published.
			 * @param {string=} required Adds `required` validation error key if the value is not entered.
			 * @param {string=} vRequired Adds `required` attribute and `required` validation constraint to
			 *    the element when the vRequired expression evaluates to true. Use `vRequired` instead of
			 *    `required` when you want to data-bind to the `required` attribute.
			 * @param {number=} vMinlength Sets `minlength` validation error key if the value is shorter than
			 *    minlength.
			 * @param {number=} vMaxlength Sets `maxlength` validation error key if the value is longer than
			 *    maxlength.
			 * @param {string=} vPattern Sets `pattern` validation error key if the value does not match the
			 *    RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
			 *    patterns defined as scope expressions.
			 * @param {string=} vChange VX expression to be executed when input changes due to user
			 *    interaction with the input element.
			 * @param {boolean=} [vTrim=true] If set to false VX will not automatically trimming the
			 *    input.
			 *
			 * @example
			 <doc:example>
			 <doc:source>
			 <script>
			 function Ctrl($scope) {
			 $scope.text = 'guest';
			 $scope.word = /^\s*\w*\s*$/;
			 }
			 </script>
			 <form name="myForm" v-controller="Ctrl">
			 Single word: <input type="text" name="input" v-model="text"
			 v-pattern="word" required v-trim="false">
			 <span class="error" v-show="myForm.input.$error.required">
			 Required!</span>
			 <span class="error" v-show="myForm.input.$error.pattern">
			 Single word only!</span>

			 <tt>text = {{text}}</tt><br/>
			 <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
			 <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
			 <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
			 <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
			 </form>
			 </doc:source>
			 <doc:scenario>
			 it('should initialize to model', function() {
			 expect(binding('text')).toEqual('guest');
			 expect(binding('myForm.input.$valid')).toEqual('true');
			 });

			 it('should be invalid if empty', function() {
			 input('text').enter('');
			 expect(binding('text')).toEqual('');
			 expect(binding('myForm.input.$valid')).toEqual('false');
			 });

			 it('should be invalid if multi word', function() {
			 input('text').enter('hello world');
			 expect(binding('myForm.input.$valid')).toEqual('false');
			 });

			 it('should not be trimmed', function() {
			 input('text').enter('untrimmed ');
			 expect(binding('text')).toEqual('untrimmed ');
			 expect(binding('myForm.input.$valid')).toEqual('true');
			 });
			 </doc:scenario>
			 </doc:example>
			 */
			'text' : textInputType,

			/**
			 * @vxdoc inputType
			 * @name vx.directive:input.number
			 *
			 * @description
			 * Text input with number validation and transformation. Sets the `number` validation
			 * error if not a valid number.
			 *
			 * @param {string} vModel Assignable vx expression to data-bind to.
			 * @param {string=} name Property name of the form under which the control is published.
			 * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`.
			 * @param {string=} max Sets the `max` validation error key if the value entered is greater than `min`.
			 * @param {string=} required Adds `required` validation error key if the value is not entered.
			 * @param {string=} vRequired Adds `required` attribute and `required` validation constraint to
			 *    the element when the vRequired expression evaluates to true. Use `vRequired` instead of
			 *    `required` when you want to data-bind to the `required` attribute.
			 * @param {number=} vMinlength Sets `minlength` validation error key if the value is shorter than
			 *    minlength.
			 * @param {number=} vMaxlength Sets `maxlength` validation error key if the value is longer than
			 *    maxlength.
			 * @param {string=} vPattern Sets `pattern` validation error key if the value does not match the
			 *    RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
			 *    patterns defined as scope expressions.
			 * @param {string=} vChange VX expression to be executed when input changes due to user
			 *    interaction with the input element.
			 *
			 * @example
			 <doc:example>
			 <doc:source>
			 <script>
			 function Ctrl($scope) {
			 $scope.value = 12;
			 }
			 </script>
			 <form name="myForm" v-controller="Ctrl">
			 Number: <input type="number" name="input" v-model="value"
			 min="0" max="99" required>
			 <span class="error" v-show="myForm.list.$error.required">
			 Required!</span>
			 <span class="error" v-show="myForm.list.$error.number">
			 Not valid number!</span>
			 <tt>value = {{value}}</tt><br/>
			 <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
			 <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
			 <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
			 <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
			 </form>
			 </doc:source>
			 <doc:scenario>
			 it('should initialize to model', function() {
			 expect(binding('value')).toEqual('12');
			 expect(binding('myForm.input.$valid')).toEqual('true');
			 });

			 it('should be invalid if empty', function() {
			 input('value').enter('');
			 expect(binding('value')).toEqual('');
			 expect(binding('myForm.input.$valid')).toEqual('false');
			 });

			 it('should be invalid if over max', function() {
			 input('value').enter('123');
			 expect(binding('value')).toEqual('');
			 expect(binding('myForm.input.$valid')).toEqual('false');
			 });
			 </doc:scenario>
			 </doc:example>
			 */
			'number' : numberInputType,

			/**
			 * @vxdoc inputType
			 * @name vx.directive:input.url
			 *
			 * @description
			 * Text input with URL validation. Sets the `url` validation error key if the content is not a
			 * valid URL.
			 *
			 * @param {string} vModel Assignable vx expression to data-bind to.
			 * @param {string=} name Property name of the form under which the control is published.
			 * @param {string=} required Adds `required` validation error key if the value is not entered.
			 * @param {string=} vRequired Adds `required` attribute and `required` validation constraint to
			 *    the element when the vRequired expression evaluates to true. Use `vRequired` instead of
			 *    `required` when you want to data-bind to the `required` attribute.
			 * @param {number=} vMinlength Sets `minlength` validation error key if the value is shorter than
			 *    minlength.
			 * @param {number=} vMaxlength Sets `maxlength` validation error key if the value is longer than
			 *    maxlength.
			 * @param {string=} vPattern Sets `pattern` validation error key if the value does not match the
			 *    RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
			 *    patterns defined as scope expressions.
			 * @param {string=} vChange VX expression to be executed when input changes due to user
			 *    interaction with the input element.
			 *
			 * @example
			 <doc:example>
			 <doc:source>
			 <script>
			 function Ctrl($scope) {
			 $scope.text = 'http://google.com';
			 }
			 </script>
			 <form name="myForm" v-controller="Ctrl">
			 URL: <input type="url" name="input" v-model="text" required>
			 <span class="error" v-show="myForm.input.$error.required">
			 Required!</span>
			 <span class="error" v-show="myForm.input.$error.url">
			 Not valid url!</span>
			 <tt>text = {{text}}</tt><br/>
			 <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
			 <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
			 <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
			 <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
			 <tt>myForm.$error.url = {{!!myForm.$error.url}}</tt><br/>
			 </form>
			 </doc:source>
			 <doc:scenario>
			 it('should initialize to model', function() {
			 expect(binding('text')).toEqual('http://google.com');
			 expect(binding('myForm.input.$valid')).toEqual('true');
			 });

			 it('should be invalid if empty', function() {
			 input('text').enter('');
			 expect(binding('text')).toEqual('');
			 expect(binding('myForm.input.$valid')).toEqual('false');
			 });

			 it('should be invalid if not url', function() {
			 input('text').enter('xxx');
			 expect(binding('myForm.input.$valid')).toEqual('false');
			 });
			 </doc:scenario>
			 </doc:example>
			 */
			'url' : urlInputType,

			/**
			 * @vxdoc inputType
			 * @name vx.directive:input.email
			 *
			 * @description
			 * Text input with email validation. Sets the `email` validation error key if not a valid email
			 * address.
			 *
			 * @param {string} vModel Assignable vx expression to data-bind to.
			 * @param {string=} name Property name of the form under which the control is published.
			 * @param {string=} required Adds `required` validation error key if the value is not entered.
			 * @param {string=} vRequired Adds `required` attribute and `required` validation constraint to
			 *    the element when the vRequired expression evaluates to true. Use `vRequired` instead of
			 *    `required` when you want to data-bind to the `required` attribute.
			 * @param {number=} vMinlength Sets `minlength` validation error key if the value is shorter than
			 *    minlength.
			 * @param {number=} vMaxlength Sets `maxlength` validation error key if the value is longer than
			 *    maxlength.
			 * @param {string=} vPattern Sets `pattern` validation error key if the value does not match the
			 *    RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
			 *    patterns defined as scope expressions.
			 * @param {string=} vChange VX expression to be executed when input changes due to user
			 *    interaction with the input element.
			 *
			 * @example
			 <doc:example>
			 <doc:source>
			 <script>
			 function Ctrl($scope) {
			 $scope.text = 'me@example.com';
			 }
			 </script>
			 <form name="myForm" v-controller="Ctrl">
			 Email: <input type="email" name="input" v-model="text" required>
			 <span class="error" v-show="myForm.input.$error.required">
			 Required!</span>
			 <span class="error" v-show="myForm.input.$error.email">
			 Not valid email!</span>
			 <tt>text = {{text}}</tt><br/>
			 <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
			 <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
			 <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
			 <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
			 <tt>myForm.$error.email = {{!!myForm.$error.email}}</tt><br/>
			 </form>
			 </doc:source>
			 <doc:scenario>
			 it('should initialize to model', function() {
			 expect(binding('text')).toEqual('me@example.com');
			 expect(binding('myForm.input.$valid')).toEqual('true');
			 });

			 it('should be invalid if empty', function() {
			 input('text').enter('');
			 expect(binding('text')).toEqual('');
			 expect(binding('myForm.input.$valid')).toEqual('false');
			 });

			 it('should be invalid if not email', function() {
			 input('text').enter('xxx');
			 expect(binding('myForm.input.$valid')).toEqual('false');
			 });
			 </doc:scenario>
			 </doc:example>
			 */
			'email' : emailInputType,

			/**
			 * @vxdoc inputType
			 * @name vx.directive:input.radio
			 *
			 * @description
			 * HTML radio button.
			 *
			 * @param {string} vModel Assignable vx expression to data-bind to.
			 * @param {string} value The value to which the expression should be set when selected.
			 * @param {string=} name Property name of the form under which the control is published.
			 * @param {string=} vChange VX expression to be executed when input changes due to user
			 *    interaction with the input element.
			 *
			 * @example
			 <doc:example>
			 <doc:source>
			 <script>
			 function Ctrl($scope) {
			 $scope.color = 'blue';
			 }
			 </script>
			 <form name="myForm" v-controller="Ctrl">
			 <input type="radio" v-model="color" value="red">  Red <br/>
			 <input type="radio" v-model="color" value="green"> Green <br/>
			 <input type="radio" v-model="color" value="blue"> Blue <br/>
			 <tt>color = {{color}}</tt><br/>
			 </form>
			 </doc:source>
			 <doc:scenario>
			 it('should change state', function() {
			 expect(binding('color')).toEqual('blue');

			 input('color').select('red');
			 expect(binding('color')).toEqual('red');
			 });
			 </doc:scenario>
			 </doc:example>
			 */
			'radio' : radioInputType,

			/**
			 * @vxdoc inputType
			 * @name vx.directive:input.checkbox
			 *
			 * @description
			 * HTML checkbox.
			 *
			 * @param {string} vModel Assignable vx expression to data-bind to.
			 * @param {string=} name Property name of the form under which the control is published.
			 * @param {string=} vTrueValue The value to which the expression should be set when selected.
			 * @param {string=} vFalseValue The value to which the expression should be set when not selected.
			 * @param {string=} vChange VX expression to be executed when input changes due to user
			 *    interaction with the input element.
			 *
			 * @example
			 <doc:example>
			 <doc:source>
			 <script>
			 function Ctrl($scope) {
			 $scope.value1 = true;
			 $scope.value2 = 'YES'
			 }
			 </script>
			 <form name="myForm" v-controller="Ctrl">
			 Value1: <input type="checkbox" v-model="value1"> <br/>
			 Value2: <input type="checkbox" v-model="value2"
			 v-true-value="YES" v-false-value="NO"> <br/>
			 <tt>value1 = {{value1}}</tt><br/>
			 <tt>value2 = {{value2}}</tt><br/>
			 </form>
			 </doc:source>
			 <doc:scenario>
			 it('should change state', function() {
			 expect(binding('value1')).toEqual('true');
			 expect(binding('value2')).toEqual('YES');

			 input('value1').check();
			 input('value2').check();
			 expect(binding('value1')).toEqual('false');
			 expect(binding('value2')).toEqual('NO');
			 });
			 </doc:scenario>
			 </doc:example>
			 */
			'checkbox' : checkboxInputType,

			'hidden' : hiddenInputType,
			'submit' : submitInputType,
			'reset' : resetInputType,
			'button' : noop

			//'password' : noop,
			//'image' : noop,
			//'file' : noop,
			//'range' : noop,

			//color
			//date
			//datetime
			//datetime-local
			//month
			//week
			//time
			//search

		};

		function getPropertyName(e) {
			return e.originalEvent ? e.originalEvent.propertyName : e.propertyName;
		}

		function textInputType(scope, element, attr, ctrl) {
			var await = attr.await ? int(attr.await) : 300;
			var listener = function(event) {
				var value = element.val();
				// By default we will trim the value
				// If the attribute v-trim exists we will avoid trimming
				// e.g. <input v-model="foo" v-trim="false">
				if (toBoolean(attr.vTrim || 'T')) {
					value = trim(value);
				}

				if (ctrl.$viewValue !== value) {
					scope.$apply(function() {
						ctrl.$setViewValue(value);
					}, ':text');
				}
			};

			if (await)
				listener = $browser.debounce(listener, await);

			// if the browser does support "input" event, we are fine - except on IE9 which doesn't fire the
			// input event on backspace, delete or cut
			if ($sniffer.hasEvent('input'))
				element.bind('input', listener);
			else {
				/*
				 element.bind('keydown', function(event) {
				 var key = event.keyCode;
				 // ignore command            modifiers                   arrows
				 if (key === 91 || (15 < key && key < 19) || (37 <= key && key <= 40))
				 return;
				 listener();
				 });
				 // if user paste into input using mouse, we need "change" event to catch it
				 if (msie <= 9) {
				 //***IMPORTANT: jimmy element.val() will trigger propertychange event, so skip it
				 var inVal, __val = element.val;
				 element.val = function(value) {
				 if (value === undefined)
				 return __val.call(this);
				 try {
				 inVal = true;
				 return __val.call(this, value);
				 } finally {
				 inVal = false;
				 }
				 };
				 element.data('input.val', element.val());
				 var fixInput = function(e) {
				 if (inVal || getPropertyName(e) !== 'value')
				 return;
				 if (element.val() !== element.data('input.val')) {
				 element.data('input.val', element.val());
				 listener();
				 }
				 };
				 if (msie > 8)//***jimmy: on IE 9, direct use attachEvent, jQuery bind not work!!!
				 element[0].attachEvent('onpropertychange', fixInput);
				 else
				 element.bind('propertychange', fixInput);
				 } else {
				 element.bind('change', listener);
				 }*/

				element.bind('keydown', function(event) {
					var key = event.keyCode;

					// ignore
					//    command            modifiers                   arrows
					if (key === 91 || (15 < key && key < 19) || (37 <= key && key <= 40))
						return;
					listener(event);
				});

				// if user paste into input using mouse, we need "change" event to catch it
				element.bind('change', listener);

				// if user modifies input value using context menu in IE, we need "paste" and "cut" events to catch it
				if ($sniffer.hasEvent('paste')) {
					element.bind('paste cut', listener);
				}
			}

			ctrl.$render = function() {
				element.val(isEmpty(ctrl.$viewValue) ? '' : ctrl.$viewValue);
			};

			ctrl.$reset = function() {
				element.val('');
				ctrl.$setViewValue('');
			};

			// min length validator
			if (attr.vMinlength) {
				var minlength = int(attr.vMinlength);
				$validation.use(ctrl, 'minlength', minlength);
			}

			// max length validator
			if (attr.vMaxlength) {
				var maxlength = int(attr.vMaxlength);
				$validation.use(ctrl, 'maxlength', maxlength);
			}

			// pattern validator
			var pattern = attr.vPattern, patternObj, match;
			if (pattern) {
				match = pattern.match(/^\/(.*)\/([gim]*)$/);
				if (match) {
					patternObj = new RegExp(match[1], match[2]);
				} else {
					patternObj = new RegExp(pattern);
				}
				$validation.use(ctrl, 'pattern', patternObj);
			}

		}

		function numberInputType(scope, element, attr, ctrl) {
			textInputType(scope, element, attr, ctrl);

			$validation.use(ctrl, 'number');

			if (attr.min) {
				var min = parseFloat(attr.min);
				$validation.use(ctrl, 'min', min);
			}

			if (attr.max) {
				var max = parseFloat(attr.max);
				$validation.use(ctrl, 'max', max);
			}

		}

		function urlInputType(scope, element, attr, ctrl) {
			textInputType(scope, element, attr, ctrl);

			$validation.use(ctrl, 'url');
		}

		function emailInputType(scope, element, attr, ctrl) {
			textInputType(scope, element, attr, ctrl);

			$validation.use(ctrl, 'email');
		}

		function radioInputType(scope, element, attr, ctrl) {
			// make the name unique, if not defined
			if (isUndefined(attr.name)) {
				element.attr('name', nextUid(inputId));
			}

			element.bind('click', function() {
				if (element[0].checked) {
					scope.$apply(function() {
						ctrl.$setViewValue(attr.value);
					}, ':radio');
				}
			});

			ctrl.$render = function() {
				var value = attr.value;
				element[0].checked = (value == ctrl.$viewValue);
			};

			ctrl.$reset = function() {
				element[0].checked = false;
				ctrl.$setViewValue(null);
			};

			attr.$observe('value', ctrl.$render);
		}

		function checkboxInputType(scope, element, attr, ctrl) {
			var trueValue = attr.vTrueValue, falseValue = attr.vFalseValue;

			if (!isString(trueValue))
				trueValue = true;
			if (!isString(falseValue))
				falseValue = false;

			element.bind('click', function() {
				scope.$apply(function() {
					ctrl.$setViewValue(element[0].checked);
				}, ':checkbox');
			});

			ctrl.$render = function() {
				element[0].checked = ctrl.$viewValue;
			};

			ctrl.$reset = function() {
				element[0].checked = false;
				ctrl.$setViewValue(null);
			};

			ctrl.$formatters.push(function(value) {
				return value === trueValue;
			});

			ctrl.$parsers.push(function(value) {
				if (value === null)
					return null;
				// for reset
				return value ? trueValue : falseValue;
			});
		}

		function hiddenInputType(scope, element, attr, ctrl) {
			// just model -> view
			ctrl.$render = function() {
				element.val(isEmpty(ctrl.$viewValue) ? '' : ctrl.$viewValue);
			};
		}

		function submitInputType(scope, element, attr, ctrl) {
			var parentForm = element.parent().controller('form');
			if (!parentForm)
				return;
			var await = attr.await ? int(attr.await) : 1000;
			// just view -> model
			var handler = function() {
				if (ctrl) {
					scope.$apply(function() {
						ctrl.$setViewValue(attr.value);
					}, ':submit');
				}
				//element.trigger('submit');
				parentForm.$submit();
			};

			if (await) {
				var h = handler;
				handler = $browser.debounce(function() {
					h();
					element.addClass('v-submitting');
				}, await, function() {
					element.removeClass('v-submitting');
				}, true);
			}

			element.bind('click', function(event) {
				event.preventDefault();
				handler();
			});
		}

		function resetInputType(scope, element, attr) {
			var parentForm = element.parent().controller('form');
			if (!parentForm)
				return;
			element.bind('click', function(event) {
				scope.$apply(function() {
					parentForm.$clearData();
					parentForm.$setPristine();
				}, ':reset');
				event.preventDefault();
			});
		}

		return {
			restrict : 'E',
			require : '?vModel',
			link : function(scope, element, attr, ctrl) {
				if (ctrl) {
					var fn;
					if (_nodeName(element) === 'BUTTON')
						fn = inputType[lowercase(attr.type)] || inputType.submit;
					else
						fn = inputType[lowercase(attr.type)] || inputType.text;
					if (fn)
						fn(scope, element, attr, ctrl);
				} else if (attr.type === 'submit') {
					inputType.submit(scope, element, attr);
				} else if (attr.type === 'reset') {
					inputType.reset(scope, element, attr);
				}
			}
		};
	}

	/**
	 * @vxdoc object
	 * @name vx.directive:vModel.vModelController
	 *
	 * @property {string} $viewValue Actual string value in the view.
	 * @property {*} $modelValue The value in the model, that the control is bound to.
	 * @property {Array.<Function>} $parsers Whenever the control reads value from the DOM, it executes
	 *     all of these functions to sanitize / convert the value as well as validate.
	 *
	 * @property {Array.<Function>} $formatters Whenever the model value changes, it executes all of
	 *     these functions to convert the value as well as validate.
	 *
	 * @property {Object} $error An object hash with all errors as keys.
	 *
	 * @property {boolean} $pristine True if user has not interacted with the control yet.
	 * @property {boolean} $dirty True if user has already interacted with the control.
	 * @property {boolean} $valid True if there is no error.
	 * @property {boolean} $invalid True if at least one error on the control.
	 *
	 * @description
	 *
	 * `vModelController` provides API for the `v-model` directive. The controller contains
	 * services for data-binding, validation, CSS update, value formatting and parsing. It
	 * specifically does not contain any logic which deals with DOM rendering or listening to
	 * DOM events. The `vModelController` is meant to be extended by other directives where, the
	 * directive provides DOM manipulation and the `vModelController` provides the data-binding.
	 *
	 * This example shows how to use `vModelController` with a custom control to achieve
	 * data-binding. Notice how different directives (`contenteditable`, `v-model`, and `required`)
	 * collaborate together to achieve the desired result.
	 *
	 * <example module="customControl">
	 <file name="style.css">
	 [contenteditable] {
	 border: 1px solid black;
	 background-color: white;
	 min-height: 20px;
	 }

	 .v-invalid {
	 border: 1px solid red;
	 }

	 </file>
	 <file name="script.js">
	 vx.module('customControl', []).
	 directive('contenteditable', function() {
	 return {
	 restrict: 'A', // only activate on element attribute
	 require: '?vModel', // get a hold of vModelController
	 link: function(scope, element, attrs, vModel) {
	 if(!vModel) return; // do nothing if no v-model

	 // Specify how UI should be updated
	 vModel.$render = function() {
	 element.html(vModel.$viewValue || '');
	 };

	 // Listen for change events to enable binding
	 element.bind('blur keyup change', function() {
	 scope.$apply(read);
	 });
	 read(); // initialize

	 // Write data to the model
	 function read() {
	 vModel.$setViewValue(element.html());
	 }
	 }
	 };
	 });
	 </file>
	 <file name="index.html">
	 <form name="myForm">
	 <div contenteditable
	 name="myWidget" v-model="userContent"
	 required>Change me!</div>
	 <span v-show="myForm.myWidget.$error.required">Required!</span>
	 <hr>
	 <textarea v-model="userContent"></textarea>
	 </form>
	 </file>
	 <file name="scenario.js">
	 it('should data-bind and become invalid', function() {
	 var contentEditable = element('[contenteditable]');

	 expect(contentEditable.text()).toEqual('Change me!');
	 input('userContent').enter('');
	 expect(contentEditable.text()).toEqual('');
	 expect(contentEditable.prop('className')).toMatch(/v-invalid-required/);
	 });
	 </file>
	 * </example>
	 *
	 */
	vModelController.$inject = ['$scope', /*'$exceptionHandler',*/'$log', '$attrs', '$element', '$parse', '$injector'];
	function vModelController($scope, /*$exceptionHandler,*/$log, $attr, $element, $parse, $injector) {
		/*jshint validthis:true*/
		this.$viewValue = Number.NaN;
		this.$modelValue = Number.NaN;
		this.$parsers = [];
		this.$formatters = [];
		this.$$parsers = [];
		this.$$formatters = [];
		this.$viewChangeListeners = [];
		this.$pristine = true;
		this.$dirty = false;
		this.$valid = true;
		this.$invalid = false;
		this.$name = $attr.name;

		var vModelGet = $parse($attr.vModel), vModelSet = vModelGet.assign;

		if (!vModelSet) {
			throw vError(116, "vModel error! Expression '{0}' is non-assignable. Element: {1}", $attr.vModel, startingTag($element));
		}

		/**
		 * @vxdoc function
		 * @name vx.directive:vModel.vModelController#$render
		 * @methodOf vx.directive:vModel.vModelController
		 *
		 * @description
		 * Called when the view needs to be updated. It is expected that the user of the v-model
		 * directive will implement this method.
		 */
		this.$render = noop;

		this.$reset = noop;

		var parentForm = $element.controller('form') || nullFormCtrl, invalidCount = 0, // used to easily determine if we are valid
		$error = this.$error = {};
		// keep invalid keys here

		var parentCtrl = $element.parent().controller('vModel');
		if (parentCtrl) {
			this.$parentModel = true;
			parentCtrl.$virtual = true;
		}

		this.$destroy = function() {
			$scope = null;
			$element = null;
		};

		// Setup initial state of the control
		$element.addClass(PRISTINE_CLASS);
		toggleValidCss($element, true);

		// convenience method for easy toggling of classes
		function toggleValidCss($element, isValid, validationErrorKey) {
			validationErrorKey = validationErrorKey ? '-' + snake_case(validationErrorKey, '-') : '';
			$element.removeClass(( isValid ? INVALID_CLASS : VALID_CLASS) + validationErrorKey).addClass(( isValid ? VALID_CLASS : INVALID_CLASS) + validationErrorKey);
		}

		/**
		 * @vxdoc function
		 * @name vx.directive:vModel.vModelController#$setValidity
		 * @methodOf vx.directive:vModel.vModelController
		 *
		 * @description
		 * Change the validity state, and notifies the form when the control changes validity. (i.e. it
		 * does not notify form if given validator is already marked as invalid).
		 *
		 * This method should be called by validators - i.e. the parser or formatter functions.
		 *
		 * @param {string} validationErrorKey Name of the validator. the `validationErrorKey` will assign
		 *        to `$error[validationErrorKey]=isValid` so that it is available for data-binding.
		 *        The `validationErrorKey` should be in camelCase and will get converted into dash-case
		 *        for class name. Example: `myError` will result in `v-valid-my-error` and `v-invalid-my-error`
		 *        class and can be bound to as  `{{someForm.someControl.$error.myError}}` .
		 * @param {boolean} isValid Whether the current state is valid (true) or invalid (false).
		 */
		this.$setValidity = function(validationErrorKey, isValid) {
			var nValid = isValid === null ? null : !isValid;
			isValid = isValid === null || !!isValid;
			if ($error[validationErrorKey] === nValid)
				return;

			if (isValid) {
				if ($error[validationErrorKey] === null || $error[validationErrorKey])
					invalidCount--;
				if (!invalidCount) {
					toggleValidCss($element, true);
					this.$valid = true;
					this.$invalid = false;
				}
			} else {
				toggleValidCss($element, false);
				this.$invalid = true;
				this.$valid = false;
				invalidCount++;
			}

			$error[validationErrorKey] = nValid;
			toggleValidCss($element, isValid, validationErrorKey);

			parentForm.$setValidity(validationErrorKey, isValid, this);
		};

		/**
		 * @vxdoc function
		 * @name vx.directive:vModel.vModelController#$setPristine
		 * @methodOf vx.directive:vModel.vModelController
		 *
		 * @description
		 * Sets the control to its pristine state.
		 *
		 * This method can be called to remove the 'v-dirty' class and set the control to its pristine
		 * state (v-pristine class).
		 */
		this.$setPristine = function() {
			this.$dirty = false;
			this.$pristine = true;
			$element.removeClass(DIRTY_CLASS).addClass(PRISTINE_CLASS);
		};

		this.$setDirty = function() {
			this.$dirty = true;
			this.$pristine = false;
			$element.removeClass(PRISTINE_CLASS).addClass(DIRTY_CLASS);
		};

		/**
		 * @vxdoc function
		 * @name vx.directive:vModel.vModelController#$setViewValue
		 * @methodOf vx.directive:vModel.vModelController
		 *
		 * @description
		 * Read a value from view.
		 *
		 * This method should be called from within a DOM event handler.
		 * For example {@link vx.directive:input input} or
		 * {@link vx.directive:select select} directives call it.
		 *
		 * It internally calls all `parsers` and if resulted value is valid, updates the model and
		 * calls all registered change listeners.
		 *
		 * @param {string} value Value from the view.
		 */
		this.$setViewValue = function(value) {
			this.$viewValue = value;

			// change to dirty
			if (this.$pristine) {
				this.$setDirty();
				if (parentCtrl)
					parentCtrl.$setDirty();
				parentForm.$setDirty();
			}

			forEach(this.$parsers, function(fn) {
				value = fn(value);
			});
			forEach(this.$$parsers, function(fn) {
				value = fnCall(fn, value);
			});

			if (this.$modelValue !== value) {
				this.$modelValue = value;
				vModelSet($scope, value);
				forEach(this.$viewChangeListeners, function(listener) {
					try {
						listener();
					} catch(e) {
						$log.error(formatError(e));
						//$exceptionHandler(e);
					}
				});
			}
		};
		// model -> value
		var ctrl = this;
		$scope.$watch(function vModelWatchAction() {
			var value = vModelGet($scope);
			// if scope model value and vModel value are out of sync
			var formatters = ctrl.$formatters, idx = formatters.length, modelChanged = ctrl.$modelValue !== value;
			if (modelChanged || ctrl.$virtual) {
				ctrl.$modelValue = value;
				while (idx--) {
					value = formatters[idx](value);
				}
			}

			formatters = ctrl.$$formatters, idx = formatters.length;
			while (idx--) {
				value = fnCall(formatters[idx], value);
			}

			if (ctrl.$virtual)// if virtual model, return value for watcher
				return value;

			if (modelChanged && ctrl.$viewValue !== value) {
				ctrl.$viewValue = value;
				ctrl.$render();
			}

		});

		function fnCall(fn, value) {
			var locals = {
				$scope : $scope,
				$value : value
			};
			// others inline dependency.
			return $injector.invoke(fn, null, locals);
		}

	}

	/**
	 * @vxdoc directive
	 * @name vx.directive:vModel
	 *
	 * @element input
	 *
	 * @description
	 * Is directive that tells VX to do two-way data binding. It works together with `input`,
	 * `select`, `textarea`. You can easily write your own directives to use `vModel` as well.
	 *
	 * `vModel` is responsible for:
	 *
	 * - binding the view into the model, which other directives such as `input`, `textarea` or `select`
	 *   require,
	 * - providing validation behavior (i.e. required, number, email, url),
	 * - keeping state of the control (valid/invalid, dirty/pristine, validation errors),
	 * - setting related css class onto the element (`v-valid`, `v-invalid`, `v-dirty`, `v-pristine`),
	 * - register the control with parent {@link vx.directive:form form}.
	 *
	 * For basic examples, how to use `vModel`, see:
	 *
	 *  - {@link vx.directive:input input}
	 *    - {@link vx.directive:input.text text}
	 *    - {@link vx.directive:input.checkbox checkbox}
	 *    - {@link vx.directive:input.radio radio}
	 *    - {@link vx.directive:input.number number}
	 *    - {@link vx.directive:input.email email}
	 *    - {@link vx.directive:input.url url}
	 *  - {@link vx.directive:select select}
	 *  - {@link vx.directive:textarea textarea}
	 *
	 */
	function vModelDirective() {
		return {
			require : ['vModel', '^?form'],
			controller : vModelController,
			link : function(scope, element, attr, ctrls) {
				// notify others, especially parent forms
				var modelCtrl = ctrls[0], formCtrl = ctrls[1] || nullFormCtrl;
				formCtrl.$addControl(modelCtrl, attr);
				element.bind('$destroy', function() {
					formCtrl.$removeControl(modelCtrl);
					modelCtrl.$destroy();
					cleanupClosure(modelCtrl);
				});
			}
		};
	}

	/**
	 * @vxdoc directive
	 * @name vx.directive:vChange
	 * @restrict E
	 *
	 * @description
	 * Evaluate given expression when user changes the input.
	 * The expression is not evaluated when the value change is coming from the model.
	 *
	 * Note, this directive requires `vModel` to be present.
	 *
	 * @element input
	 *
	 * @example
	 * <doc:example>
	 *   <doc:source>
	 *     <script>
	 *       function Controller($scope) {
	 *         $scope.counter = 0;
	 *         $scope.change = function() {
	 *           $scope.counter++;
	 *         };
	 *       }
	 *     </script>
	 *     <div v-controller="Controller">
	 *       <input type="checkbox" v-model="confirmed" v-change="change()" id="v-change-example1" />
	 *       <input type="checkbox" v-model="confirmed" id="v-change-example2" />
	 *       <label for="v-change-example2">Confirmed</label><br />
	 *       debug = {{confirmed}}<br />
	 *       counter = {{counter}}
	 *     </div>
	 *   </doc:source>
	 *   <doc:scenario>
	 *     it('should evaluate the expression if changing from view', function() {
	 *       expect(binding('counter')).toEqual('0');
	 *       element('#v-change-example1').click();
	 *       expect(binding('counter')).toEqual('1');
	 *       expect(binding('confirmed')).toEqual('true');
	 *     });
	 *
	 *     it('should not evaluate the expression if changing from model', function() {
	 *       element('#v-change-example2').click();
	 *       expect(binding('counter')).toEqual('0');
	 *       expect(binding('confirmed')).toEqual('true');
	 *     });
	 *   </doc:scenario>
	 * </doc:example>
	 */
	vChangeDirective.$inject = ['$$remote'];
	function vChangeDirective($$remote) {
		return {
			require : 'vModel',
			link : function(scope, element, attr, ctrl) {
				ctrl.$viewChangeListeners.push(function() {
					scope.$eval(attr.vChange, injectRemote(element, null, attr.vChange, false, $$remote));
				});
			}
		};
	}

	function requiredDirective() {
		function checkArray(data) {
			for (var i = 0; i < data.length; i++) {
				if (isValidItem(data[i])) {
					return true;
				}
			}
			return false;
		}

		return {
			require : '?vModel',
			link : function(scope, elm, attr, ctrl) {
				if (!ctrl)
					return;
				attr.required = true;
				// force truthy in case we are on non input element
				var validator = function(value) {
					if (attr.required && ((isArray(value) && !checkArray(value)) || (isEmpty(value) || value === false))) {
						ctrl.$setValidity('required', false);
						return null;
					} else {
						ctrl.$setValidity('required', true);
						return value;
					}
				};

				ctrl.$formatters.push(validator);
				ctrl.$parsers.unshift(validator);

				attr.$observe('required', function() {
					validator(ctrl.$viewValue);
				});

			}
		};
	}

	/**
	 * @vxdoc directive
	 * @name vx.directive:vList
	 *
	 * @description
	 * Text input that converts between comma-separated string into an array of strings.
	 *
	 * @element input
	 * @param {string=} vList optional delimiter that should be used to split the value. If
	 *   specified in form `/something/` then the value will be converted into a regular expression.
	 *
	 * @example
	 <doc:example>
	 <doc:source>
	 <script>
	 function Ctrl($scope) {
	 $scope.names = ['igor', 'misko', 'vojta'];
	 }
	 </script>
	 <form name="myForm" v-controller="Ctrl">
	 List: <input name="namesInput" v-model="names" v-list required>
	 <span class="error" v-show="myForm.list.$error.required">
	 Required!</span>
	 <tt>names = {{names}}</tt><br/>
	 <tt>myForm.namesInput.$valid = {{myForm.namesInput.$valid}}</tt><br/>
	 <tt>myForm.namesInput.$error = {{myForm.namesInput.$error}}</tt><br/>
	 <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
	 <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
	 </form>
	 </doc:source>
	 <doc:scenario>
	 it('should initialize to model', function() {
	 expect(binding('names')).toEqual('["igor","misko","vojta"]');
	 expect(binding('myForm.namesInput.$valid')).toEqual('true');
	 });

	 it('should be invalid if empty', function() {
	 input('names').enter('');
	 expect(binding('names')).toEqual('[]');
	 expect(binding('myForm.namesInput.$valid')).toEqual('false');
	 });
	 </doc:scenario>
	 </doc:example>
	 */
	/*
	function vListDirective() {
		return {
			require : 'vModel',
			link : function(scope, element, attr, ctrl) {
				var match = /\/(.*)\//.exec(attr.vList), separator = match && new RegExp(match[1]) || attr.vList || ',';

				var parse = function(viewValue) {
					var list = [];
					if (viewValue) {
						forEach(viewValue.split(separator), function(value) {
							if (value)
								list.push(trim(value));
						});
					}
					return list;
				};

				ctrl.$parsers.push(parse);
				ctrl.$formatters.push(function(value) {
					if (isArray(value)) {
						return value.join(', ');
					}
					return undefined;
				});
			}
		};
	}
	*/
	/*
	function vValueDirective() {
		var CONSTANT_VALUE_REGEXP = /^(true|false|\d+)$/;
		return {
			priority : 100,
			compile : function(tpl, tplAttr) {
				if (CONSTANT_VALUE_REGEXP.test(tplAttr.vValue)) {
					return function(scope, elm, attr) {
						attr.$set('value', scope.$eval(attr.vValue));
					};
				} else {
					return function(scope, elm, attr) {
						scope.$watch(attr.vValue, function valueWatchAction(value) {
							attr.$set('value', value, false);
						});
					};
				}
			}
		};
	}
	*/

	/**
	 * @vxdoc directive
	 * @name vx.directive:select
	 * @restrict E
	 *
	 * @description
	 * HTML `SELECT` element with vx data-binding.
	 *
	 * # `vOptions`
	 *
	 * Optionally `vOptions` attribute can be used to dynamically generate a list of `<option>`
	 * elements for a `<select>` element using an array or an object obtained by evaluating the
	 * `vOptions` expression.
	 *˝˝
	 * When an item in the select menu is select, the value of array element or object property
	 * represented by the selected option will be bound to the model identified by the `vModel`
	 * directive of the parent select element.
	 *
	 * Optionally, a single hard-coded `<option>` element, with the value set to an empty string, can
	 * be nested into the `<select>` element. This element will then represent `null` or "not selected"
	 * option. See example below for demonstration.
	 *
	 * Note: `vOptions` provides iterator facility for `<option>` element which should be used instead
	 * of {@link vx.directive:vRepeat vRepeat} when you want the
	 * `select` model to be bound to a non-string value. This is because an option element can currently
	 * be bound to string values only.
	 *
	 * @param {string} vModel Assignable vx expression to data-bind to.
	 * @param {string=} name Property name of the form under which the control is published.
	 * @param {string=} required The control is considered valid only if value is entered.
	 * @param {string=} vRequired Adds `required` attribute and `required` validation constraint to
	 *    the element when the vRequired expression evaluates to true. Use `vRequired` instead of
	 *    `required` when you want to data-bind to the `required` attribute.
	 * @param {comprehension_expression=} vOptions in one of the following forms:
	 *
	 *   * for array data sources:
	 *     * `label` **`for`** `value` **`in`** `array`
	 *     * `select` **`as`** `label` **`for`** `value` **`in`** `array`
	 *     * `label`  **`group by`** `group` **`for`** `value` **`in`** `array`
	 *     * `select` **`as`** `label` **`group by`** `group` **`for`** `value` **`in`** `array`
	 *     * `select` **`as`** `label` **`group by`** `group` **`for`** `value` **`in`** `array` **`track by`** `trackexpr`
	 *   * for object data sources:
	 *     * `label` **`for (`**`key` **`,`** `value`**`) in`** `object`
	 *     * `select` **`as`** `label` **`for (`**`key` **`,`** `value`**`) in`** `object`
	 *     * `label` **`group by`** `group` **`for (`**`key`**`,`** `value`**`) in`** `object`
	 *     * `select` **`as`** `label` **`group by`** `group`
	 *         **`for` `(`**`key`**`,`** `value`**`) in`** `object`
	 *
	 * Where:
	 *
	 *   * `array` / `object`: an expression which evaluates to an array / object to iterate over.
	 *   * `value`: local variable which will refer to each item in the `array` or each property value
	 *      of `object` during iteration.
	 *   * `key`: local variable which will refer to a property name in `object` during iteration.
	 *   * `label`: The result of this expression will be the label for `<option>` element. The
	 *     `expression` will most likely refer to the `value` variable (e.g. `value.propertyName`).
	 *   * `select`: The result of this expression will be bound to the model of the parent `<select>`
	 *      element. If not specified, `select` expression will default to `value`.
	 *   * `group`: The result of this expression will be used to group options using the `<optgroup>`
	 *      DOM element.
	 *   * `trackexpr`: Used when working with an array of objects. The result of this expression will be
	 *      used to identify the objects in the array. The `trackexpr` will most likely refer to the
	 *     `value` variable (e.g. `value.propertyName`).
	 *
	 * @example
	 <doc:example>
	 <doc:source>
	 <script>
	 function MyCntrl($scope) {
	 $scope.colors = [
	 {name:'black', shade:'dark'},
	 {name:'white', shade:'light'},
	 {name:'red', shade:'dark'},
	 {name:'blue', shade:'dark'},
	 {name:'yellow', shade:'light'}
	 ];
	 $scope.color = $scope.colors[2]; // red
	 }
	 </script>
	 <div v-controller="MyCntrl">
	 <ul>
	 <li v-repeat="color in colors">
	 Name: <input v-model="color.name">
	 [<a href v-click="colors.splice($index, 1)">X</a>]
	 </li>
	 <li>
	 [<a href v-click="colors.push({})">add</a>]
	 </li>
	 </ul>
	 <hr/>
	 Color (null not allowed):
	 <select v-model="color" v-options="c.name for c in colors"></select><br>

	 Color (null allowed):
	 <span  class="nullable">
	 <select v-model="color" v-options="c.name for c in colors">
	 <option value="">-- chose color --</option>
	 </select>
	 </span><br/>

	 Color grouped by shade:
	 <select v-model="color" v-options="c.name group by c.shade for c in colors">
	 </select><br/>

	 Select <a href v-click="color={name:'not in list'}">bogus</a>.<br>
	 <hr/>
	 Currently selected: {{ {selected_color:color}  }}
	 <div style="border:solid 1px black; height:20px"
	 v-style="{'background-color':color.name}">
	 </div>
	 </div>
	 </doc:source>
	 <doc:scenario>
	 it('should check v-options', function() {
	 expect(binding('{selected_color:color}')).toMatch('red');
	 select('color').option('0');
	 expect(binding('{selected_color:color}')).toMatch('black');
	 using('.nullable').select('color').option('');
	 expect(binding('{selected_color:color}')).toMatch('null');
	 });
	 </doc:scenario>
	 </doc:example>
	 */
	selectDirective.$inject = ['$compile', '$parse'];
	function selectDirective($compile, $parse) {
		//0000111110000000000022220000000000000000000000333300000000000000444444444444444440000000005555555555555555500000006666666666666666600000000000000007777000000000000000000088888
		var V_OPTIONS_REGEXP = /^\s*(.*?)(?:\s+as\s+(.*?))?(?:\s+group\s+by\s+(.*))?\s+for\s+(?:([\$\w][\$\w\d]*)|(?:\(\s*([\$\w][\$\w\d]*)\s*,\s*([\$\w][\$\w\d]*)\s*\)))\s+in\s+(.*?)(?:\s+track\s+by\s+(.*?))?$/, nullModelCtrl = {
			$setViewValue : noop
		};
		// we can't just jqLite('<option>') since jqLite is not smart enough
		// to create it in <select> and IE barfs otherwise.
		var optionTemplate = jqLite(document.createElement('option')), optGroupTemplate = jqLite(document.createElement('optgroup'));
		return {
			restrict : 'E',
			require : ['select', '?vModel'],
			controller : ['$element', '$scope', '$attrs',
			function($element, $scope, $attrs) {
				var self = this, optionsMap = {}, vModelCtrl = nullModelCtrl, nullOption, unknownOption;
				self.databound = $attrs.vModel;
				self.init = function(vModelCtrl_, nullOption_, unknownOption_) {
					vModelCtrl = vModelCtrl_;
					nullOption = nullOption_;
					unknownOption = unknownOption_;
				};

				self.addOption = function(value) {
					optionsMap[value] = true;
					if (vModelCtrl.$viewValue == value) {
						$element.val(value);
						if (unknownOption.parent())
							unknownOption.remove();
					}
				};

				self.removeOption = function(value) {
					if (this.hasOption(value)) {
						delete optionsMap[value];
						if (vModelCtrl.$viewValue == value) {
							this.renderUnknownOption(value);
						}
					}
				};

				self.renderUnknownOption = function(val) {
					var unknownVal = '? ' + hashKey(val) + ' ?';
					unknownOption.val(unknownVal);
					$element.prepend(unknownOption);
					$element.val(unknownVal);
					unknownOption.prop('selected', true);
					// needed for IE
				};

				self.hasOption = function(value) {
					return optionsMap.hasOwnProperty(value);
				};

				//$scope.$on('$destroy', function() {
				// disable unknown option so that we don't do work when the whole select is being destroyed
				//	self.renderUnknownOption = noop;
				//});

				$element.bind('$destroy', function() {
					cleanupClosure(self);
					if (msie)
						IE_GC(unknownOption[0]);
				});
			}],

			link : function(scope, element, attr, ctrls) {
				// if vModel is not defined, we don't need to do anything
				if (!ctrls[1])
					return;

				var selectCtrl = ctrls[0], vModelCtrl = ctrls[1], multiple = attr.multiple, optionsExp = attr.vOptions, nullOption = false, // if false, user will not be able to select it (used by vOptions)
				emptyOption, unknownOption = optionTemplate.clone();

				// find "null" option
				for (var i = 0, children = element.children(), ii = children.length; i < ii; i++) {
					if (children[i].value === '') {
						emptyOption = nullOption = jqLite(children[i]);
						break;
					}
				}

				selectCtrl.init(vModelCtrl, nullOption, unknownOption);

				// required validator
				if (multiple && (attr.required || attr.vRequired)) {
					var requiredValidator = function(value) {
						vModelCtrl.$setValidity('required', !attr.required || !!(value && value.length));
						return value;
					};

					vModelCtrl.$parsers.push(requiredValidator);
					vModelCtrl.$formatters.unshift(requiredValidator);

					attr.$observe('required', function() {
						requiredValidator(vModelCtrl.$viewValue);
					});
				}

				if (optionsExp)
					_Options(scope, element, vModelCtrl);
				else if (multiple)
					_Multiple(scope, element, vModelCtrl);
				else
					_Single(scope, element, vModelCtrl, selectCtrl);

				////////////////////////////

				function _Single(scope, selectElement, vModelCtrl, selectCtrl) {
					vModelCtrl.$render = function() {
						var viewValue = vModelCtrl.$viewValue;

						if (selectCtrl.hasOption(viewValue)) {
							if (unknownOption.parent())
								unknownOption.remove();
							selectElement.val(viewValue);
							if (viewValue === '')
								emptyOption.prop('selected', true);
							// to make IE9 happy
						} else {
							if (isUndefined(viewValue) && emptyOption) {
								selectElement.val('');
							} else {
								selectCtrl.renderUnknownOption(viewValue);
							}
						}
					};

					selectElement.bind('change', function() {
						scope.$apply(function() {
							if (unknownOption.parent())
								unknownOption.remove();
							vModelCtrl.$setViewValue(selectElement.val());
						}, ':select');
					});
				}

				function _Multiple(scope, selectElement, ctrl) {
					var lastView;
					ctrl.$render = function() {
						var items = new HashMap(ctrl.$viewValue);
						forEach(selectElement.find('option'), function(option) {
							option.selected = isDefined(items.get(option.value));
						});
					};
					// we have to do it on each watch since vModel watches reference, but
					// we need to work of an array, so we need to see if anything was inserted/removed
					scope.$watch(function selectMultipleWatch() {
						if (!equals(lastView, ctrl.$viewValue)) {
							lastView = copy(ctrl.$viewValue);
							ctrl.$render();
						}
					});

					selectElement.bind('change', function() {
						scope.$apply(function() {
							var array = [];
							forEach(selectElement.find('option'), function(option) {
								if (option.selected) {
									array.push(option.value);
								}
							});
							ctrl.$setViewValue(array);
						}, ':select');
					});
				}

				function _Options(scope, selectElement, ctrl) {
					var match;

					if (!( match = optionsExp.match(V_OPTIONS_REGEXP))) {
						throw vError(117, "vOptions error! Expected expression in form of '_select_ (as _label_)? for (_key_,)?_value_ in _collection_' but got '{0}'. Element: {1}", optionsExp, startingTag(selectElement));
					}

					var displayFn = $parse(match[2] || match[1]), valueName = match[4] || match[6], keyName = match[5], //
					groupByFn = $parse(match[3] || ''), valueFn = $parse(match[2] ? match[1] : valueName), valuesFn = $parse(match[7]), //
					track = match[8], trackFn = track ? $parse(match[8]) : null,
					// This is an array of array of existing option groups in DOM. We try to reuse these if possible
					// optionGroupsCache[0] is the options with no option group
					// optionGroupsCache[?][0] is the parent: either the SELECT or OPTGROUP element
					optionGroupsCache = [[{
						element : selectElement,
						label : ''
					}]];

					if (nullOption) {
						// compile the element since there might be bindings in it
						$compile(nullOption)(scope, null, false);

						// remove the class, which is added automatically because we recompile the element and it
						// becomes the compilation root
						//nullOption.removeClass('v-scope');

						// we need to remove it before calling selectElement.html('') because otherwise IE will
						// remove the label from the element. wtf?
						nullOption.remove();
					}

					// clear contents, we'll add what's needed based on the model
					selectElement.html('');

					selectElement.bind('change', function() {
						scope.$apply(function() {
							var optionGroup, collection = valuesFn(scope) || [], locals = {}, key, value, optionElement, index, groupIndex, length, groupLength, trackIndex;

							if (multiple) {
								value = [];
								for ( groupIndex = 0, groupLength = optionGroupsCache.length; groupIndex < groupLength; groupIndex++) {
									// list of options for that group. (first item has the parent)
									optionGroup = optionGroupsCache[groupIndex];

									for ( index = 1, length = optionGroup.length; index < length; index++) {
										if ((optionElement = optionGroup[index].element)[0].selected) {
											key = optionElement.val();
											if (keyName)
												locals[keyName] = key;
											if (trackFn) {
												for ( trackIndex = 0; trackIndex < collection.length; trackIndex++) {
													locals[valueName] = collection[trackIndex];
													if (trackFn(scope, locals) == key)
														break;
												}
											} else {
												locals[valueName] = collection[key];
											}
											value.push(valueFn(scope, locals));
										}
									}
								}
							} else {
								key = selectElement.val();
								if (key === '?') {
									value = undefined;
								} else if (key === '') {
									value = null;
								} else {
									if (trackFn) {
										for ( trackIndex = 0; trackIndex < collection.length; trackIndex++) {
											locals[valueName] = collection[trackIndex];
											if (trackFn(scope, locals) == key) {
												value = valueFn(scope, locals);
												break;
											}
										}
									} else {
										locals[valueName] = collection[key];
										if (keyName)
											locals[keyName] = key;
										value = valueFn(scope, locals);
									}
								}
							}
							ctrl.$setViewValue(value);
						}, ':select');
					});

					ctrl.$render = render;

					// TODO(vojta): can't we optimize this ?
					scope.$watch(render);

					function render() {
						var optionGroups = {
							'' : []
						}, // Temporary location for the option groups before we render them
						optionGroupNames = [''], optionGroupName, optionGroup, option, existingParent, existingOptions, //
						existingOption, modelValue = ctrl.$modelValue, values = valuesFn(scope) || [], keys = keyName ? sortedKeys(values) : values, //
						groupLength, length, groupIndex, index, locals = {}, selected, selectedSet = false, // nothing is selected yet
						lastElement, element;

						if (multiple) {
							if (trackFn && isArray(modelValue)) {
								selectedSet = new HashMap([]);
								for (var trackIndex = 0; trackIndex < modelValue.length; trackIndex++) {
									locals[valueName] = modelValue[trackIndex];
									selectedSet.put(trackFn(scope, locals), modelValue[trackIndex]);
								}
							} else {
								selectedSet = new HashMap(modelValue);
							}
						}

						// We now build up the list of options we need (we merge later)
						for ( index = 0, length = keys.length; index < length; index++) {
							locals[valueName] = values[ keyName ? locals[keyName] = keys[index] : index];
							optionGroupName = groupByFn(scope, locals) || '';
							if (!( optionGroup = optionGroups[optionGroupName])) {
								optionGroup = optionGroups[optionGroupName] = [];
								optionGroupNames.push(optionGroupName);
							}
							if (multiple) {
								selected = selectedSet.remove( trackFn ? trackFn(scope, locals) : valueFn(scope, locals)) !== undefined;
							} else {
								if (trackFn) {
									var modelCast = {};
									modelCast[valueName] = modelValue;
									selected = trackFn(scope, modelCast) === trackFn(scope, locals);
								} else {
									selected = modelValue === valueFn(scope, locals);
								}
								selectedSet = selectedSet || selected;
								// see if at least one item is selected
							}
							var displayLabel = displayFn(scope, locals);
							//*** modify by jimmy, for '0' or false
							optionGroup.push({
								id : trackFn ? trackFn(scope, locals) : ( keyName ? keys[index] : index), // either the index into array or key from object
								label : isEmpty(displayLabel) ? '' : displayLabel, // what will be seen by the user
								selected : selected // determine if we should be selected
							});
						}

						if (!multiple) {
							if (nullOption || modelValue === null) {
								// insert null option if we have a placeholder, or the model is null
								optionGroups[''].unshift({
									id : '',
									label : '',
									selected : !selectedSet
								});
							} else if (!selectedSet) {
								// option could not be found, we have to insert the undefined item
								optionGroups[''].unshift({
									id : '?',
									label : '',
									selected : true
								});
							}
						}

						// Now we need to update the list of DOM nodes to match the optionGroups we computed above
						for ( groupIndex = 0, groupLength = optionGroupNames.length; groupIndex < groupLength; groupIndex++) {
							// current option group name or '' if no group
							optionGroupName = optionGroupNames[groupIndex];

							// list of options for that group. (first item has the parent)
							optionGroup = optionGroups[optionGroupName];

							if (optionGroupsCache.length <= groupIndex) {
								// we need to grow the optionGroups
								existingParent = {
									element : optGroupTemplate.clone().attr('label', optionGroupName),
									label : optionGroup.label
								};
								existingOptions = [existingParent];
								optionGroupsCache.push(existingOptions);
								selectElement.append(existingParent.element);
							} else {
								existingOptions = optionGroupsCache[groupIndex];
								existingParent = existingOptions[0];
								// either SELECT (no group) or OPTGROUP element

								// update the OPTGROUP label if not the same.
								if (existingParent.label != optionGroupName) {
									existingParent.element.attr('label', existingParent.label = optionGroupName);
								}
							}
							lastElement = null;
							// start at the beginning
							for ( index = 0, length = optionGroup.length; index < length; index++) {
								option = optionGroup[index];
								if (( existingOption = existingOptions[index + 1])) {
									// reuse elements
									lastElement = existingOption.element;
									if (existingOption.label !== option.label) {
										lastElement.text(existingOption.label = option.label);
									}
									if (existingOption.id !== option.id) {
										lastElement.val(existingOption.id = option.id);
									}
									// lastElement.prop('selected') provided by jQuery has side-effects
									if (lastElement[0].selected !== option.selected) {
										lastElement.prop('selected', (existingOption.selected = option.selected));
									}
								} else {
									// grow elements

									// if it's a null option
									if (option.id === '' && nullOption) {
										// put back the pre-compiled element
										element = nullOption;
									} else {
										// jQuery(v1.4.2) Bug: We should be able to chain the method calls, but
										// in this version of jQuery on some browser the .text() returns a string
										// rather then the element.
										( element = optionTemplate.clone()).val(option.id).text(option.label);
										if (option.selected)
											element.attr('selected', option.selected);
										else
											element.removeAttr('selected');
									}

									existingOptions.push( existingOption = {
										element : element,
										label : option.label,
										id : option.id,
										selected : option.selected
									});
									if (lastElement) {
										lastElement.after(element);
									} else {
										existingParent.element.append(element);
									}
									lastElement = element;
								}
							}
							// remove any excessive OPTIONs in a group
							index++;
							// increment since the existingOptions[0] is parent element not OPTION
							while (existingOptions.length > index) {
								existingOptions.pop().element.remove();
							}
						}
						// remove any excessive OPTGROUPs from select
						while (optionGroupsCache.length > groupIndex) {
							optionGroupsCache.pop()[0].element.remove();
						}

						// for IE dynamic render bug
						//if (msie) {
						//	selectElement.css('display', 'none');
						//	selectElement.css('display', '');
						//}

						selectElement.bind('$destroy', function() {
							optionGroupsCache = [];
						});
					}

				}

			}
		};
	}

	function vOptionsDirective() {
		return {
			terminal : true
		};
	}

	// option directive
	optionDirective.$inject = ['$interpolate'];
	function optionDirective($interpolate) {
		var nullSelectCtrl = {
			addOption : noop,
			removeOption : noop
		};
		return {
			restrict : 'E',
			priority : 100,
			compile : function(element, attr) {
				if (isUndefined(attr.value)) {
					var interpolateFn = $interpolate(element.text(), true);
					if (!interpolateFn) {
						attr.$set('value', element.text());
					}
				}

				return function(scope, element, attr) {
					var selectCtrlName = '$selectController', parent = element.parent(), selectCtrl = parent.data(selectCtrlName) || parent.parent().data(selectCtrlName);
					// in case we are in optgroup

					if (selectCtrl && selectCtrl.databound) {
						// For some reason Opera defaults to true and if not overridden this messes up the repeater.
						// We don't want the view to drive the initialization of the model anyway.
						element.prop('selected', false);
					} else {
						selectCtrl = nullSelectCtrl;
					}

					if (interpolateFn) {
						scope.$watch(interpolateFn, function interpolateWatchAction(newVal, oldVal) {
							attr.$set('value', newVal);
							if (newVal !== oldVal)
								selectCtrl.removeOption(oldVal);
							selectCtrl.addOption(newVal);
						});
					} else {
						selectCtrl.addOption(attr.value);
					}

					element.bind('$destroy', function() {
						selectCtrl.removeOption(attr.value);
					});
				};
			}
		};
	}

	// v-val directive
	/*
	vValDirective.$inject = ['$validation', "$parse"];
	function vValDirective($validation, $parse) {
		function splitFn(str, ctrl) {
			var last = 0, length = str.length, type = 0, quot, colon = false, regex = false;
			for (var i = 0, ch, ch0; i < length; i++) {
				ch = str.charAt(i);
				// IE 6,7 cannot use str[i];
				if (ch === '\'' || ch === '"') {
					if (ch0 !== '\\') {
						if (!quot)
							quot = ch;
						else if (quot === ch)
							quot = undefined;
					}
				} else if (ch === '(') {
					if (!quot && !regex)
						colon = true;
				} else if (ch === ')') {
					if (!quot && !regex) {
						colon = false;
						type = 1;
					}
				} else if (ch === ',') {
					if (!colon && !regex) {
						useVal(type, trim(str.substring(last, i)), ctrl);
						last = i + 1;
						type = 0;
					}
				} else if (ch === '/') {
					if (!quot && ch0 !== '\\') {
						regex = !regex;
						if (!regex)
							type = 2;
					}
				}
				ch0 = ch;
			}
			useVal(type, trim(str.substring(last, length)), ctrl);
		}

		function useVal(type, fn, ctrl) {
			var alias;
			if (fn.charAt(0) === ':') {
				var i = type === 2 ? fn.indexOf('/') : fn.indexOf('(');
				alias = fn.substring(0, i);
				fn = fn.substring(i);
			}
			if (type === 2) {// direct regex
				return $validation.use(ctrl, alias || 'pattern', fn);
			} else {
				if (type === 1) {// for function call
					// normalize string's escape, need for $parse call string literal
					fn = fn.replace(/\\\\/g, '\\').replace(/\\/g, '\\\\');
				} else {// type === 0, for expression alias
					fn = fn + '()';
				}
				if (fn.charAt(0) === '(') {
					return $validation.use(ctrl, alias || 'evaluate', fn);
				}
				var f = $parse(fn)($validation.validators);
				if (f) {
					$validation.use(ctrl, f);
				} else {
					throw vError(118, 'no validator: {0}', fn);
				}
			}
		}

		return {
			require : 'vModel',
			link : function(scope, element, attr, ctrl) {
				var validateExpr = trim(attr.vVal);
				splitFn(validateExpr, ctrl);
			}
		};

	}*/

	// --- Directives End --- //
	var IE_GC = vx.IE_GC = noop;

	vxSetup(vx);
	jqLite(document).ready(function() {
		vxInit(document, bootstrap);
		if (msie) {
			var gcDiv = jqLite('<div id="IE_GC_BIN" style="display:none;" />')[0];
			jqLite(document).find('body').append(gcDiv);
			IE_GC = vx.IE_GC = function(el) {
				gcDiv.appendChild(el);
				gcDiv.innerHTML = '';
			};
		}
	});
})(window, document, window.$);

//vx.element(document).find('head').append('<style type="text/css">@charset "UTF-8";[v\\:cloak],[v-cloak],[data-v-cloak],[x-v-cloak],.v-cloak,.x-v-cloak{display:none;}v\\:form{display:block;}</style>');
